We use cookies (including Google cookies) to personalize ads and analyze traffic. By continuing to use our site, you accept our Privacy Policy.

Promise Pool

Number: 2750

Difficulty: Medium

Paid? Yes

Companies: Yandex, TikTok, Patreon


Problem Description

Given an array of asynchronous functions and a pool limit n, implement an asynchronous function promisePool that executes these functions under the constraint that no more than n promises are running concurrently. The promisePool should resolve when all asynchronous functions have finished executing.


Key Insights

  • Use a concurrency control mechanism to limit the number of actively running promises.
  • Maintain an index or pointer to track which function from the input array should be executed next.
  • Upon the resolution of any promise, start a new one if available until all functions have been processed.
  • The overall task is complete when there are no functions left and all running promises have resolved.

Space and Time Complexity

Time Complexity: O(m), where m is the number of functions to execute. Space Complexity: O(n) for the active pool of concurrent promises.


Solution

We can solve the problem by maintaining an index that tracks which asynchronous function to execute next. We define a helper routine (or executor) that:

  1. Checks if there is a function left to run.
  2. If yes, increments the index and awaits the result of running that function.
  3. Once the function completes, the routine recursively calls itself to pick up the next function. We start n such routines (to respect the pool limit) and use Promise.all (or the equivalent in other languages) to wait until all concurrent routines have finished executing. This structure ensures that we never run more than n promises concurrently and that a new promise starts as soon as one finishes.

Code Solutions

import asyncio

async def promise_pool(functions, n):
    # Shared index among all tasks.
    i = 0

    async def worker():
        nonlocal i
        while i < len(functions):
            # Fetch the current function and increment the index for next worker.
            fn = functions[i]
            i += 1
            # Await the async function.
            await fn()

    # Create n worker tasks.
    tasks = [asyncio.create_task(worker()) for _ in range(n)]
    # Wait until all worker tasks finish.
    await asyncio.gather(*tasks)

# Example usage:
if __name__ == "__main__":
    async def async_task(delay):
        await asyncio.sleep(delay)

    functions = [
        lambda: async_task(0.3),
        lambda: async_task(0.4),
        lambda: async_task(0.2)
    ]
    asyncio.run(promise_pool(functions, 2))
← Back to All Questions