Prefork Worker Pool
Spawn child processes for true CPU parallelism — each child has its own GIL.
Spawn child processes for true CPU parallelism — each child has its own GIL.
Spawn separate child processes for true CPU parallelism. Each child has its own Python GIL (Global Interpreter Lock — only one thread runs Python bytecode at a time), so CPU-bound tasks don't block each other.
| Workload | Recommended pool | Why |
|---|---|---|
| I/O-bound (HTTP calls, DB queries) | thread (default) | Threads release the GIL during I/O |
| CPU-bound (data processing, ML) | prefork | Each process owns its GIL |
| Mixed workloads | prefork | CPU tasks benefit; I/O tasks work fine too |
queue = Queue(db_path="myapp.db", workers=4)
queue.run_worker(pool="prefork", app="myapp:queue")flexiq worker --app myapp:queue --pool preforkThe app parameter tells each child process how to import your Queue
instance. It must be an importable path in module:attribute format.
Mapping from Celery: --pool prefork / --concurrency N ≈ flexiq's
--pool prefork / workers=N. The default pool differs, though — flexiq
defaults to thread, while Celery defaults to prefork.
PreforkPool frames each job as a JSON header line followed by the task payload's raw bytes, and writes it to the least-loaded child's stdin pipe| Parameter | Type | Default | Description |
|---|---|---|---|
pool | str | "thread" | Set to "prefork" to enable |
app | str | — | Import path to Queue instance (required) |
workers | int | CPU count | Number of child processes |
The thread pool is the default. To switch to prefork:
# Before (thread pool)
queue.run_worker()
# After (prefork)
queue.run_worker(pool="prefork", app="myapp:queue")Everything else stays the same — task decorators, middleware, resources, events, and the scheduler all work identically. The only difference is where task code executes (child process vs. worker thread).
Children inherit the parent's stderr, so print() statements and Python
logging appear in the parent's terminal.
Enable debug logging to see child lifecycle events:
import logging
logging.getLogger("flexiq.prefork.child").setLevel(logging.DEBUG)Log output includes:
child ready (app=..., pid=...) — child initialized and waiting for jobsexecuting task_name[job_id] — job received (DEBUG level)task task_name[job_id] failed: ... — task errorshutdown received — clean shutdownresource teardown error — resource cleanup failure