A spawned worker imports the main module again, so process creation must not run during import.
Python multiprocessing spawn: keep startup behind the main guard
Operation contract
The receipt calculation is a top-level function that a fresh interpreter can import. The process and queue are created only under the main guard. An explicit spawn context makes the behavior visible even on a system whose default differs. The parent receives one result and joins the child before declaring success.
Failure and ownership boundary
This source must run from a real file; pasting it into a REPL does not provide an importable main module. Queue.get has a timeout, but if it expires the owner still needs to stop and join the worker in a production error path. The fixture's worker exits normally, so it does not prove crash recovery, queue persistence, or safe forced termination.
Working program
from multiprocessing import get_context
def revise_receipt(quantity, outbound):
outbound.put(quantity + 1)
if __name__ == "__main__":
context = get_context("spawn")
outbound = context.Queue()
worker = context.Process(target=revise_receipt, args=(46, outbound))
worker.start()
print("revision", outbound.get(timeout=3))
worker.join(timeout=3)
print("exit", worker.exitcode)
outbound.close()
outbound.join_thread()Output
revision 47
exit 0Costs and limits
Spawn starts another interpreter and serializes arguments. That setup costs much more than this addition; process work needs enough CPU load to justify it.
Common Mistakes
- A nested function or REPL lambda may not be importable by a spawned child.
- A queue result is not a durable job acknowledgement.
- A timed-out get does not release a still-running child.
Connected lessons
- Python thread pools: collect results and observe worker failures
- Python subprocess timeout: kill and reap the timed-out child
- Python package layout: owned imports and module entrypoints
Continue with Python InterpreterPoolExecutor: pass results across isolated runtimes.
