#406Semaphore-Bounded Concurrent TasksMedium

Semaphore-Bounded Concurrent Tasks

Background

A semaphore caps how many concurrent operations run at once. For parallel agents, it prevents fan-out from blowing past an external API rate limit. The simplest implementation processes tasks in waves of at most max_concurrent.

Problem statement

Implement run_bounded(tasks, max_concurrent). Tasks are 0-arg callables; process them in successive waves of at most max_concurrent; return results in original task order.

Input

  • taskslist[Callable[[], Any]], list of 0-arg callables.
  • max_concurrentint >= 1, the per-wave cap.

Output

Returns list of results, length len(tasks), in the original order.

Examples

Example 1 — results preserve order

Input:  tasks = [() -> 2*i for i in 0..5], max_concurrent=2
Output: [0, 2, 4, 6, 8, 10]

Example 2 — max_concurrent >= len → single wave

Input:  tasks=[() -> 1, () -> 2], max_concurrent=10
Output: [1, 2]

Example 3 — empty tasks

Input:  tasks=[], max_concurrent=3
Output: []

Constraints

  • max_concurrent >= 1. ValueError otherwise.
  • Output length and order match input.
  • Empty input returns [].

Notes

  • Real concurrency. With asyncio.gather or a thread pool, tasks within a wave would run truly in parallel. This kernel demonstrates the slicing pattern; production code adds the actual parallel executor.
  • Adaptive sizing. Some agent stacks raise max_concurrent until they hit a 429, then back off — the semaphore size becomes a learned hyperparameter.
Python
Loading...

▶ Run executes the 3 visible sample tests below in your browser. Submit runs the full suite — including hidden tests — on the server for an official verdict.

  • Example: results preserve order
  • Example: single wave when max exceeds length
  • Reference: exactly divisible waves