Async Pool — Асинхронный пул
Пул объектов с асинхронной операцией ожидания. Если все инстансы заняты —
awaitпока освободится. Современная замена callback-based пулов.
Проблема
Классический Object Pool: если все инстансы заняты, нужно ждать. На callback'ах — некрасиво. Хочется await pool.acquire.
Решение
- Хранить очередь ожидающих промисов (
queue). acquireвозвращает промис: если есть свободные — резолвится сразу, иначе — попадает вqueue.release(inst)— сначала проверяетqueue: если есть ожидающий — резолвит ему. Иначе — возвращает вfree.
Пример в JS
class AsyncPool {
#factory; #size;
#instances = ;
#free = ;
#queue = ;
constructor(factory, size) {
this.#factory = factory;
this.#size = size;
for (let i = 0; i < size; i++) {
const inst = factory;
this.#instances.push(inst);
this.#free.push(inst);
}
}
acquire {
if (this.#free.length) {
return Promise.resolve(this.#free.pop());
}
return new Promise((resolve) => this.#queue.push(resolve));
}
release(inst) {
const waiter = this.#queue.shift();
if (waiter) {
waiter(inst); // отдаём ожидающему
} else {
this.#free.push(inst); // возвращаем в свободные
}
}
}
// использование
const pool = new AsyncPool( => makeConnection, 5);
const conn = await pool.acquire;
try { await conn.query('SELECT 1'); }
finally { pool.release(conn); }
Где используется в JS-экосистеме
- pg-pool, mysql2.createPool — встроенные async-пулы
- generic-pool на npm — универсальный async-пул
- worker_threads pool под нагрузку
- HTTP-агент с keep-alive — внутренний async-пул соединений
- p-limit, p-queue на npm — concurrent task pools
Подводные камни
- Утечки: забыл
release— пул иссякнет,acquireзависнет навсегда. - Таймаут на acquire — без него можно зависнуть надолго.
- Backpressure — если producer быстрее consumer'а, queue растёт.
finallyобязателен для надёжного release.- Реинициализация инстанса перед release — иначе state предыдущего вызова попадёт в следующий.
Главные тезисы автора
- «Async Pool — это пул, который позволяет подождать через какой-нибудь контракт».
- Современная замена callback — async/await удобнее.
- acquire возвращает промис — резолвится сразу или попадает в очередь.
- release достаёт из очереди ожидающих перед возвратом в free.
- Counter
available— оптимизация, чтобы не перебирать всю коллекцию. - Динамический рост возможен сверх initial size, но с лимитом памяти.
- Фабрика в конструкторе — пул сам инстанцирует, удобнее.
🎓 Источники
- 🎓 AsyncPool — шаблон асинхронный пул · 2024-11-02
- Контракт с async/await
- Очередь ожидающих промисов
- Counter available
- Динамический рост сверх initial
- 🎓 Паттерны замедляют или ускоряют — Разбор Async Pool · 2025-11-11
- Производительность Async Pool в V8