Memory-budget-aware parallel execution pool for Python
Project description
budgetpool
Memory-budget-aware parallel execution pool for Python.
A drop-in replacement for ProcessPoolExecutor that calculates safe worker counts based on available memory, prevents OOM crashes, and provides backpressure on task submission.
Why?
ProcessPoolExecutor spawns workers based on CPU count, ignoring memory.
When each worker loads a large dataset or model, this easily causes OOM kills:
# Dangerous — 8 workers × 3GB each = 24GB on a 16GB machine
with ProcessPoolExecutor(max_workers=os.cpu_count()) as pool:
results = list(pool.map(run_backtest, param_grid))
BudgetPool fixes this by computing safe worker counts from your memory budget:
from budgetpool import BudgetPool
# Safe — fits within 12GB, 2GB per worker → 6 workers max
with BudgetPool(memory_budget_gb=12.0, memory_per_worker_gb=2.0) as pool:
results = list(pool.map(run_backtest, param_grid))
Install
pip install budgetpool
Quick Start
Basic Usage
from budgetpool import BudgetPool
with BudgetPool(memory_per_worker_gb=2.0) as pool:
results = list(pool.map(heavy_func, items))
print(f"Used {pool.num_workers} workers")
With Explicit Budget
with BudgetPool(
memory_budget_gb=12.0, # Total budget for all workers
memory_per_worker_gb=2.0, # Estimated peak per worker
max_workers=8, # CPU cap (optional)
) as pool:
futures = [pool.submit(process, item) for item in items]
results = [f.result() for f in futures]
Memory Monitoring
from budgetpool import get_memory_info, safe_worker_count
# Check system memory
info = get_memory_info()
print(f"Total: {info.total_gb:.1f}GB, Available: {info.available_gb:.1f}GB")
print(f"Safe for workers: {info.free_for_workers_gb:.1f}GB")
# Calculate worker count without creating a pool
n = safe_worker_count(memory_per_worker_gb=3.0)
print(f"Safe worker count: {n}")
How It Works
- Startup: Reads system memory (via
psutil), respects cgroup limits in containers - Worker calculation:
min(budget ÷ per_worker, cpu_count, max_workers) - Backpressure: Blocks
submit()when pending tasks exceedmax_pending(default: 2× workers) - Runtime checks: Warns at 85% memory usage, raises
MemoryBudgetExceededat 95%
API Reference
BudgetPool
| Parameter | Type | Default | Description |
|---|---|---|---|
memory_budget_gb |
float | None |
Auto-detect | Total memory budget for all workers |
memory_per_worker_gb |
float |
1.0 |
Estimated peak memory per worker |
max_workers |
int | None |
CPU count | Hard cap on worker count |
max_pending |
int | None |
2 × workers |
Backpressure threshold |
warn_at_percent |
float | None |
85.0 |
Log warning at this memory % |
fail_at_percent |
float | None |
95.0 |
Raise error at this memory % |
mp_context |
None |
Multiprocessing start method | |
on_task_complete |
Callable | None |
None |
Callback fired on each task completion |
Methods: submit(), map(), shutdown() — same signatures as ProcessPoolExecutor.
Properties: num_workers, memory_budget_gb, memory_info, stats.
PoolStats
Cumulative statistics available via pool.stats:
| Field | Type | Description |
|---|---|---|
tasks_submitted |
int |
Total tasks submitted |
tasks_completed |
int |
Successfully completed tasks |
tasks_failed |
int |
Tasks that raised exceptions |
memory_warnings |
int |
Times memory warning threshold was hit |
peak_memory_percent |
float |
Highest observed system memory % |
safe_worker_count(memory_per_worker_gb, max_workers=None) → int
Standalone function to calculate safe worker count without creating a pool.
get_memory_info() → MemoryInfo
Returns a MemoryInfo dataclass with total_gb, available_gb, used_gb, percent, and free_for_workers_gb.
CLI
Check system memory and safe worker counts:
$ python -m budgetpool status
System Memory
Total: 16.0 GB
Available: 6.5 GB
Used: 8.1 GB (60%)
Free for workers: 4.5 GB
Safe Worker Counts
0.5 GB/worker → 8 workers
1.0 GB/worker → 4 workers
2.0 GB/worker → 2 workers
4.0 GB/worker → 1 workers
8.0 GB/worker → 1 workers
Container Support
budgetpool automatically detects cgroup v1/v2 memory limits, so it works correctly inside Docker containers where psutil.virtual_memory().total would report host memory:
docker run --memory=4g python -c "
from budgetpool import get_memory_info
print(get_memory_info().total_gb) # → 4.0, not host memory
"
Requirements
- Python 3.10+
- psutil ≥ 5.9.0
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file budgetpool-0.2.0.tar.gz.
File metadata
- Download URL: budgetpool-0.2.0.tar.gz
- Upload date:
- Size: 10.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9e52ece366f7d983e6a5462fceacd08df198e6cc472cc59c4eaa1807147db8ee
|
|
| MD5 |
1da25ac1a53b5c00878270a8eeeffa1d
|
|
| BLAKE2b-256 |
8c39e365b12fe79c5e9a526827886aab897508a74ed3c48ad1ab039a94df0ab9
|
File details
Details for the file budgetpool-0.2.0-py3-none-any.whl.
File metadata
- Download URL: budgetpool-0.2.0-py3-none-any.whl
- Upload date:
- Size: 12.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8d925f75d344df28af3106e5faeac530c007212cbba4363c42fa9f3c5294ed73
|
|
| MD5 |
5ebe8f9bb3910ce5b4c6eac856c01138
|
|
| BLAKE2b-256 |
1b76eb8c15ff62567d18d3646c43a70541edd6af2a0ccc508b5f04df4f5d14ac
|