### Configure Process Start Method with get_context Source: https://context7.com/celery/billiard/llms.txt Configure the process start method globally or using a context object. This example shows querying available methods, setting a global method, and using a context for isolated configuration with Queues and Pools. ```python import billiard # Query available methods print(billiard.get_all_start_methods()) # ['fork', 'spawn', 'forkserver'] on Linux # Global setting (call once, at program start) billiard.set_start_method('spawn') # Or use a context object for isolated configuration ctx = billiard.get_context('fork') q = ctx.Queue() p = ctx.Process(target=lambda: q.put(42)) p.start() p.join() print(q.get()) # 42 # Pool from context with ctx.Pool(2) as pool: print(pool.map(lambda x: x**2, range(5))) # [0, 1, 4, 9, 16] # Platform-aware guard for spawn/forkserver entry point if __name__ == "__main__": billiard.freeze_support() # required when using spawn in frozen (PyInstaller) executables ``` -------------------------------- ### Install multiprocessing using setup.py Source: https://github.com/celery/billiard/blob/main/INSTALL.txt Use this command to install the multiprocessing package from source if you have a C compiler set up. This is the standard installation method for most systems. ```shell python setup.py install ``` -------------------------------- ### Basic Process Creation and Execution Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md Demonstrates the basic usage of creating a Process object, starting it, and waiting for it to complete using `start()` and `join()`. ```python from multiprocessing import Process def f(name): print('hello', name) if __name__ == '__main__': p = Process(target=f, args=('bob',)) p.start() p.join() ``` -------------------------------- ### Starting a Manager Server Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md Illustrates how to obtain and start a SyncManager object, which controls a server process for managing shared objects. ```python from multiprocessing.managers import BaseManager manager = BaseManager(address=('', 50000), authkey=b'abc') server = manager.get_server() server.serve_forever() ``` -------------------------------- ### Install Sphinx and build documentation Source: https://github.com/celery/billiard/blob/main/INSTALL.txt Install Sphinx and setuptools using easy_install, then build the standalone documentation. This requires setuptools version 0.6c9 or newer and Sphinx 0.5. ```shell sudo easy_install-2.5 "Sphinx>=0.5" make doc ``` -------------------------------- ### start() Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md Starts the process's activity by arranging for the `run()` method to be invoked in a separate process. Must be called at most once per process object. ```APIDOC ## start() ### Description Start the process’s activity. This must be called at most once per process object. It arranges for the object’s `run()` method to be invoked in a separate process. ``` -------------------------------- ### Multiprocessing Pool Example Setup Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md This code sets up a test environment for `multiprocessing.Pool`, defining various worker functions like `calculate`, `mul`, `plus`, `f`, `pow3`, and `noop`. It includes helper functions for process management and result formatting. ```python # # A test of `multiprocessing.Pool` class # # Copyright (c) 2006-2008, R Oudkerk # All rights reserved. # import multiprocessing import time import random import sys # # Functions used by test code # def calculate(func, args): result = func(*args) return '%s says that %s%s = %s' % ( multiprocessing.current_process().name, func.__name__, args, result ) def calculatestar(args): return calculate(*args) def mul(a, b): time.sleep(0.5*random.random()) return a * b def plus(a, b): time.sleep(0.5*random.random()) return a + b def f(x): return 1.0 / (x-5.0) def pow3(x): return x**3 def noop(x): pass # # Test code ``` -------------------------------- ### Process Class with Process Info Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md An expanded example demonstrating how to get information about the current process, including its parent process ID and its own process ID, within a spawned process. ```APIDOC ## Process Class with Process Info ### Description This example illustrates how to obtain and print process-specific information such as module name, parent process ID, and the current process ID within a function executed by a separate process. ### Method `Process(target=None, args=(), **kwargs)` ### Endpoint N/A (Python module) ### Parameters #### Path Parameters N/A #### Query Parameters N/A #### Request Body N/A ### Request Example ```python from multiprocessing import Process import os def info(title): print(title) print('module name:', __name__) print('parent process:', os.getppid()) print('process id:', os.getpid()) def f(name): info('function f') print('hello', name) if __name__ == '__main__': info('main line') p = Process(target=f, args=('bob',)) p.start() p.join() ``` ### Response #### Success Response (200) N/A (This is a code execution example, not an API response) #### Response Example N/A ``` -------------------------------- ### Start Method / Context Source: https://context7.com/celery/billiard/llms.txt Configure the process start method for Billiard. Supports 'fork', 'spawn', and 'forkserver'. The start method can be set globally or scoped to a specific context object. ```APIDOC ## Start Method / Context ### `billiard.get_context()` / `billiard.set_start_method()` Configure process start method. Billiard supports `fork` (default on Linux), `spawn` (default on macOS ≥10.14 and Windows), and `forkserver`. The start method can be set globally or scoped to a specific context object. ### Usage ```python import billiard # Query available methods print(billiard.get_all_start_methods()) # ['fork', 'spawn', 'forkserver'] on Linux # Global setting (call once, at program start) billiard.set_start_method('spawn') # Or use a context object for isolated configuration ctx = billiard.get_context('fork') q = ctx.Queue() p = ctx.Process(target=lambda: q.put(42)) p.start() p.join() print(q.get()) # 42 # Pool from context with ctx.Pool(2) as pool: print(pool.map(lambda x: x**2, range(5))) # [0, 1, 4, 9, 16] # Platform-aware guard for spawn/forkserver entry point if __name__ == "__main__": billiard.freeze_support() # required when using spawn in frozen (PyInstaller) executables ``` ``` -------------------------------- ### Multiprocessing Server Example Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md Demonstrates how to create a simple HTTP server that is handled by multiple worker processes. This example shows process creation and inter-process communication via shared server objects. ```python import os import sys from multiprocessing import Process, current_process, freeze_support from BaseHTTPServer import HTTPServer from SimpleHTTPServer import SimpleHTTPRequestHandler if sys.platform == 'win32': import multiprocessing.reduction # make sockets pickable/inheritable def note(format, *args): sys.stderr.write('[%s]\t%s\n' % (current_process().name, format%args)) class RequestHandler(SimpleHTTPRequestHandler): # we override log_message() to show which process is handling the request def log_message(self, format, *args): note(format, *args) def serve_forever(server): note('starting server') try: server.serve_forever() except KeyboardInterrupt: pass def runpool(address, number_of_processes): # create a single server object -- children will each inherit a copy server = HTTPServer(address, RequestHandler) # create child processes to act as workers for i in range(number_of_processes-1): Process(target=serve_forever, args=(server,)).start() # main process also acts as a worker serve_forever(server) def test(): DIR = os.path.join(os.path.dirname(__file__), '..') ADDRESS = ('localhost', 8000) NUMBER_OF_PROCESSES = 4 print 'Serving at http://%s:%d using %d worker processes' % \ (ADDRESS[0], ADDRESS[1], NUMBER_OF_PROCESSES) print 'To exit press Ctrl-' + ['C', 'Break'][sys.platform=='win32'] os.chdir(DIR) runpool(ADDRESS, NUMBER_OF_PROCESSES) if __name__ == '__main__': freeze_support() test() ``` -------------------------------- ### Custom Managers and Proxies Example Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md Demonstrates creating and using customized managers and proxies with `multiprocessing.managers`. This example shows how to register custom classes and functions, control exposed methods, and use custom proxy types for generators. ```python # # This module shows how to use arbitrary callables with a subclass of # `BaseManager`. # # Copyright (c) 2006-2008, R Oudkerk # All rights reserved. # from multiprocessing import freeze_support from multiprocessing.managers import BaseManager, BaseProxy import operator ## class Foo(object): def f(self): print 'you called Foo.f()' def g(self): print 'you called Foo.g()' def _h(self): print 'you called Foo._h()' # A simple generator function def baz(): for i in xrange(10): yield i*i # Proxy type for generator objects class GeneratorProxy(BaseProxy): _exposed_ = ('next', '__next__') def __iter__(self): return self def next(self): return self._callmethod('next') def __next__(self): return self._callmethod('__next__') # Function to return the operator module def get_operator_module(): return operator ## class MyManager(BaseManager): pass # register the Foo class; make `f()` and `g()` accessible via proxy MyManager.register('Foo1', Foo) # register the Foo class; make `g()` and `_h()` accessible via proxy MyManager.register('Foo2', Foo, exposed=('g', '_h')) # register the generator function baz; use `GeneratorProxy` to make proxies MyManager.register('baz', baz, proxytype=GeneratorProxy) # register get_operator_module(); make public functions accessible via proxy MyManager.register('operator', get_operator_module) ## def test(): manager = MyManager() manager.start() print '-' * 20 f1 = manager.Foo1() f1.f() f1.g() assert not hasattr(f1, '_h') assert sorted(f1._exposed_) == sorted(['f', 'g']) print '-' * 20 f2 = manager.Foo2() f2.g() f2._h() assert not hasattr(f2, 'f') assert sorted(f2._exposed_) == sorted(['g', '_h']) print '-' * 20 it = manager.baz() for i in it: print '<%d>' % i, print print '-' * 20 op = manager.operator() print 'op.add(23, 45) =', op.add(23, 45) print 'op.pow(2, 94) =', op.pow(2, 94) print 'op.getslice(range(10), 2, 6) =', op.getslice(range(10), 2, 6) print 'op.repeat(range(5), 3) =', op.repeat(range(5), 3) print 'op._exposed_ =', op._exposed_ ## if __name__ == '__main__': freeze_support() test() ``` -------------------------------- ### Worker Process Example with Queues Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md Demonstrates using queues for task distribution and result collection among worker processes. Results may not be in order. ```python # # Simple example which uses a pool of workers to carry out some tasks. # # Notice that the results will probably not come out of the output # queue in the same in the same order as the corresponding tasks were # put on the input queue. If it is important to get the results back # in the original order then consider using `Pool.map()` or # `Pool.imap()` (which will save on the amount of code needed anyway). # # Copyright (c) 2006-2008, R Oudkerk # All rights reserved. # import time import random from multiprocessing import Process, Queue, current_process, freeze_support # # Function run by worker processes # def worker(input, output): for func, args in iter(input.get, 'STOP'): result = calculate(func, args) output.put(result) # # Function used to calculate result # def calculate(func, args): result = func(*args) return '%s says that %s%s = %s' % \ (current_process().name, func.__name__, args, result) # # Functions referenced by tasks # def mul(a, b): time.sleep(0.5*random.random()) return a * b def plus(a, b): time.sleep(0.5*random.random()) return a + b # # # def test(): NUMBER_OF_PROCESSES = 4 TASKS1 = [(mul, (i, 7)) for i in range(20)] TASKS2 = [(plus, (i, 8)) for i in range(10)] # Create queues task_queue = Queue() done_queue = Queue() # Submit tasks for task in TASKS1: task_queue.put(task) # Start worker processes for i in range(NUMBER_OF_PROCESSES): Process(target=worker, args=(task_queue, done_queue)).start() # Get and print results print 'Unordered results:' for i in range(len(TASKS1)): print '\t', done_queue.get() # Add more tasks using `put()` for task in TASKS2: task_queue.put(task) # Get and print some more results for i in range(len(TASKS2)): print '\t', done_queue.get() # Tell child processes to stop for i in range(NUMBER_OF_PROCESSES): task_queue.put('STOP') if __name__ == '__main__': freeze_support() test() ``` -------------------------------- ### Process Information and Execution Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md An expanded example showing how to print process-specific information like parent process ID and process ID within a spawned process. ```python from multiprocessing import Process import os def info(title): print(title) print('module name:', __name__) print('parent process:', os.getppid()) print('process id:', os.getpid()) def f(name): info('function f') print('hello', name) if __name__ == '__main__': info('main line') p = Process(target=f, args=('bob',)) p.start() p.join() ``` -------------------------------- ### Multiprocessing Test Setup Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md Sets up and runs tests for the multiprocessing module, allowing selection between processes, a manager, or threads. ```python def test(namespace=multiprocessing): global multiprocessing multiprocessing = namespace for func in [ test_value, test_queue, test_condition, test_semaphore, test_join_timeout, test_event, test_sharedvalues ]: print '\n\t######## %s\n' % func.__name__ func() ignore = multiprocessing.active_children() # cleanup any old processes if hasattr(multiprocessing, '_debug_info'): info = multiprocessing._debug_info() if info: print info raise ValueError, 'there should be no positive refcounts left' if __name__ == '__main__': multiprocessing.freeze_support() assert len(sys.argv) in (1, 2) if len(sys.argv) == 1 or sys.argv[1] == 'processes': print ' Using processes '.center(79, '-') namespace = multiprocessing elif sys.argv[1] == 'manager': print ' Using processes and a manager '.center(79, '-') namespace = multiprocessing.Manager() namespace.Process = multiprocessing.Process namespace.current_process = multiprocessing.current_process namespace.active_children = multiprocessing.active_children elif sys.argv[1] == 'threads': print ' Using threads '.center(79, '-') import multiprocessing.dummy as namespace else: print 'Usage:\n\t%s [processes | manager | threads]' % sys.argv[0] raise SystemExit, 2 test(namespace) ``` -------------------------------- ### Process Class Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md Demonstrates the creation and basic usage of the Process class for spawning new processes. Includes starting a process and waiting for it to complete using join(). ```APIDOC ## Process Class Usage ### Description This example shows how to create a `Process` object, assign a target function to it, and then start and join the process. ### Method `Process(target=None, args=(), **kwargs)` ### Endpoint N/A (Python module) ### Parameters #### Path Parameters N/A #### Query Parameters N/A #### Request Body N/A ### Request Example ```python from multiprocessing import Process def f(name): print('hello', name) if __name__ == '__main__': p = Process(target=f, args=('bob',)) p.start() p.join() ``` ### Response #### Success Response (200) N/A (This is a code execution example, not an API response) #### Response Example N/A ``` -------------------------------- ### Configure multiprocessing build for Unix Source: https://github.com/celery/billiard/blob/main/INSTALL.txt Modify the 'macros' dictionary and 'libraries' list in setup.py for specific Unix environments. This example shows settings for POSIX semaphores and real-time libraries. ```python macros = dict( HAVE_SEM_OPEN=1, HAVE_SEM_TIMEDWAIT=1, HAVE_FD_TRANSFER=1 ) libraries = ['rt'] ``` -------------------------------- ### daemon Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md The process's daemon flag (Boolean). Must be set before `start()` is called. Inherits from the creating process by default. ```APIDOC ## daemon ### Description The process’s daemon flag, a Boolean value. This must be set before `start()` is called. The initial value is inherited from the creating process. When a process exits, it attempts to terminate all of its daemonic child processes. Note that a daemonic process is not allowed to create child processes. Otherwise a daemonic process would leave its children orphaned if it gets terminated when its parent process exits. Additionally, these are **not** Unix daemons or services, they are normal processes that will be terminated (and not joined) if non-daemonic processes have exited. ### Versionchanged Changed in version 3.3: Added the *daemon* argument. ``` -------------------------------- ### Multiprocessing Pool Example Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md Demonstrates the creation and usage of a multiprocessing Pool for parallel task execution using apply_async, imap, imap_unordered, and map. Includes basic benchmarking and error handling tests. ```python import multiprocessing import time import sys def mul(x, y): return x * y def plus(x, y): return x + y def calculate(func, args): return func(*args) def calculatestar(args): return calculatestar(*args) def pow3(x): return x**3 def noop(x): pass def f(x): return x / 0 def test(): print 'cpu_count() = %d\n' % multiprocessing.cpu_count() # # Create pool # PROCESSES = 4 print 'Creating pool with %d processes\n' % PROCESSES pool = multiprocessing.Pool(PROCESSES) print 'pool = %s' print # # Tests # TASKS = [(mul, (i, 7)) for i in range(10)] + \ [(plus, (i, 8)) for i in range(10)] results = [pool.apply_async(calculate, t) for t in TASKS] imap_it = pool.imap(calculatestar, TASKS) imap_unordered_it = pool.imap_unordered(calculatestar, TASKS) print 'Ordered results using pool.apply_async():' for r in results: print '\t', r.get() print print 'Ordered results using pool.imap():' for x in imap_it: print '\t', x print print 'Unordered results using pool.imap_unordered():' for x in imap_unordered_it: print '\t', x print print 'Ordered results using pool.map() --- will block till complete:' for x in pool.map(calculatestar, TASKS): print '\t', x print # # Simple benchmarks # N = 100000 print 'def pow3(x): return x**3' t = time.time() A = map(pow3, xrange(N)) print '\tmap(pow3, xrange(%d)):\n\t\t%s seconds' % \ (N, time.time() - t) t = time.time() B = pool.map(pow3, xrange(N)) print '\tpool.map(pow3, xrange(%d)):\n\t\t%s seconds' % \ (N, time.time() - t) t = time.time() C = list(pool.imap(pow3, xrange(N), chunksize=N//8)) print '\tlist(pool.imap(pow3, xrange(%d), chunksize=%d)):\n\t\t%s' \ ' seconds' % (N, N//8, time.time() - t) assert A == B == C, (len(A), len(B), len(C)) print L = [None] * 1000000 print 'def noop(x): pass' print 'L = [None] * 1000000' t = time.time() A = map(noop, L) print '\tmap(noop, L):\n\t\t%s seconds' % \ (time.time() - t) t = time.time() B = pool.map(noop, L) print '\tpool.map(noop, L):\n\t\t%s seconds' % \ (time.time() - t) t = time.time() C = list(pool.imap(noop, L, chunksize=len(L)//8)) print '\tlist(pool.imap(noop, L, chunksize=%d)):\n\t\t%s seconds' % \ (len(L)//8, time.time() - t) assert A == B == C, (len(A), len(B), len(C)) print del A, B, C, L # # Test error handling # print 'Testing error handling:' try: print pool.apply(f, (5,)) except ZeroDivisionError: print '\tGot ZeroDivisionError as expected from pool.apply()' else: raise AssertionError, 'expected ZeroDivisionError' try: print pool.map(f, range(10)) except ZeroDivisionError: print '\tGot ZeroDivisionError as expected from pool.map()' else: raise AssertionError, 'expected ZeroDivisionError' try: print list(pool.imap(f, range(10))) except ZeroDivisionError: print '\tGot ZeroDivisionError as expected from list(pool.imap())' else: raise AssertionError, 'expected ZeroDivisionError' it = pool.imap(f, range(10)) for i in range(10): try: x = it.next() except ZeroDivisionError: if i == 5: pass except StopIteration: break else: if i == 5: raise AssertionError, 'expected ZeroDivisionError' assert i == 9 print '\tGot ZeroDivisionError as expected from IMapIterator.next()' print # # Testing timeouts # print 'Testing ApplyResult.get() with timeout:', res = pool.apply_async(calculate, TASKS[0]) while 1: sys.stdout.flush() try: sys.stdout.write('\n\t%s' % res.get(0.02)) break except multiprocessing.TimeoutError: sys.stdout.write('.') print print print 'Testing IMapIterator.next() with timeout:', it = pool.imap(calculatestar, TASKS) while 1: sys.stdout.flush() try: sys.stdout.write('\n\t%s' % it.next(0.02)) except StopIteration: break except multiprocessing.TimeoutError: sys.stdout.write('.') print print # # Testing callback # print 'Testing callback:' A = [] B = [56, 0, 1, 8, 27, 64, 125, 216, 343, 512, 729] r = pool.apply_async(mul, (7, 8), callback=A.append) r.wait() r = pool.map_async(pow3, range(10), callback=A.extend) r.wait() if A == B: print '\tcallbacks succeeded\n' else: print '\t*** callbacks failed\n\t\t%s != %s\n' % (A, B) # # Check there are no outstanding tasks # assert not pool._cache, 'cache = %r' % pool._cache # # Check close() methods # print 'Testing close():' for worker in pool._pool: assert worker.is_alive() result = pool.apply_async(time.sleep, [0.5]) pool.close() pool.join() assert result.get() is None for worker in pool._pool: pass if __name__ == '__main__': test() ``` -------------------------------- ### is_alive() Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md Returns `True` if the process is alive (started and not yet terminated), `False` otherwise. ```APIDOC ## is_alive() ### Description Return whether the process is alive. Roughly, a process object is alive from the moment the `start()` method returns until the child process terminates. ``` -------------------------------- ### Creating a Process Pool Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md Initialize a Pool to manage worker processes. The number of processes defaults to the CPU count if not specified. An initializer function can be provided to run setup code in each worker. ```python multiprocessing.Pool(processes=None, initializer=None, initargs=(), maxtasksperchild=None) ``` -------------------------------- ### Manager / SyncManager Source: https://context7.com/celery/billiard/llms.txt Starts a server process to host shared objects. Clients obtain proxy objects whose method calls are forwarded to the server. SyncManager exposes various synchronization primitives and data structures. ```APIDOC ## `billiard.Manager()` — server process hosting shared objects `Manager()` starts a background server process. Clients obtain proxy objects whose method calls are forwarded to the server. `SyncManager` exposes `Lock`, `RLock`, `Semaphore`, `BoundedSemaphore`, `Condition`, `Event`, `Queue`, `list`, `dict`, `Value`, `Array`, and `Namespace`. ### Usage Example ```python import billiard def worker(d, lst, lock, idx): with lock: d[idx] = idx * idx lst.append(idx) manager = billiard.Manager() shared_dict = manager.dict() shared_list = manager.list() shared_lock = manager.Lock() procs = [ billiard.Process(target=worker, args=(shared_dict, shared_list, shared_lock, i)) for i in range(5) ] for p in procs: p.start() for p in procs: p.join() print(dict(shared_dict)) # {0:0, 1:1, 2:4, 3:9, 4:16} print(sorted(shared_list)) # [0, 1, 2, 3, 4] # Shared counter using Value counter = manager.Value('i', 0) counter_lock = manager.Lock() def increment(val, lk): for _ in range(100): with lk: val.value += 1 procs = [billiard.Process(target=increment, args=(counter, counter_lock)) for i in range(4)] for p in procs: p.start() for p in procs: p.join() print(counter.value) # 400 # Namespace ns = manager.Namespace() ns.x = 42 ns.label = "shared" print(ns.x, ns.label) manager.shutdown() ``` ``` -------------------------------- ### Basic Pool Usage Example Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md Demonstrates the fundamental usage of multiprocessing.Pool for parallel task execution, including applying a function asynchronously, mapping a function over an iterable, and using imap for lazy iteration. Includes error handling for asynchronous results. ```python from multiprocessing import Pool def f(x): return x*x if __name__ == '__main__': pool = Pool(processes=4) # start 4 worker processes result = pool.apply_async(f, (10,)) # evaluate "f(10)" asynchronously print(result.get(timeout=1)) # prints "100" unless your computer is *very* slow print(pool.map(f, range(10))) # prints "[0, 4, ..., 81]" it = pool.imap(f, range(10)) print(next(it)) # prints "0" print(next(it)) # prints "1" print(it.next(timeout=1)) # prints "4" unless your computer is *very* slow import time result = pool.apply_async(time.sleep, (10,)) print(result.get(timeout=1)) # raises TimeoutError ``` -------------------------------- ### Initialize and Use billiard.Pool Source: https://context7.com/celery/billiard/llms.txt Demonstrates initializing a billiard.Pool with various configuration options including timeouts, restart limits, and lifecycle callbacks. Shows synchronous map, apply, asynchronous apply with callbacks, and lazy iteration. Also includes dynamic resizing and context manager usage. ```python import billiard from billiard.exceptions import SoftTimeLimitExceeded, TimeLimitExceeded, WorkerLostError import signal, time def heavy(x): if x == 3: time.sleep(10) # will be killed by hard timeout return x ** 2 def on_up(worker): print(f"Worker started: {worker.pid}") def on_down(worker): print(f"Worker exited: {worker.pid}") if __name__ == "__main__": pool = billiard.Pool( processes=4, initializer=None, maxtasksperchild=100, # recycle workers after 100 tasks timeout=5.0, # hard kill after 5 s soft_timeout=3.0, # SIGUSR1 after 3 s (SoftTimeLimitExceeded) lost_worker_timeout=10.0, max_restarts=200, max_restart_freq=1, on_process_up=on_up, on_process_down=on_down, allow_restart=True, ) # Synchronous map results = pool.map(heavy, [1, 2, 4, 5]) print(results) # [1, 4, 16, 25] (3 was skipped / timed out) # apply — blocks until result is ready val = pool.apply(lambda x: x * 10, args=(7,)) print(val) # 70 # apply_async with callbacks def on_result(r): print(f"Done: {r}") def on_error(e): print(f"Error: {e}") ar = pool.apply_async( heavy, args=(2,), callback=on_result, error_callback=on_error, timeout=5.0, soft_timeout=2.0, ) try: print(ar.get(timeout=6)) # 4 except (TimeLimitExceeded, WorkerLostError) as e: print(f"Task failed: {e}") # Lazy iteration for result in pool.imap(lambda x: x + 1, range(10), chunksize=2): print(result) # Dynamic resizing pool.grow(2) # add 2 workers pool.shrink(1) # remove 1 idle worker pool.close() pool.join() # Context manager (calls terminate on exit) with billiard.Pool(2) as p: print(p.map(str, range(5))) ``` -------------------------------- ### multiprocessing.managers.BaseManager Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md Create a BaseManager object. After creation, start() or get_server().serve_forever() must be called to ensure the manager object refers to a started manager process. ```APIDOC ## class multiprocessing.managers.BaseManager() ### Description Create a BaseManager object. Once created one should call [`start()`](#multiprocessing.managers.BaseManager.start) or `get_server().serve_forever()` to ensure that the manager object refers to a started manager process. *address* is the address on which the manager process listens for new connections. If *address* is `None` then an arbitrary one is chosen. *authkey* is the authentication key which will be used to check the validity of incoming connections to the server process. If *authkey* is `None` then `current_process().authkey`. Otherwise *authkey* is used and it must be a string. ### Methods #### start(initializer=None, initargs=()) Start a subprocess to start the manager. If *initializer* is not `None` then the subprocess will call `initializer(*initargs)` when it starts. #### get_server() Returns a `Server` object which represents the actual server under the control of the Manager. The `Server` object supports the `serve_forever()` method. #### connect() Connect a local manager object to a remote manager process. #### shutdown() Stop the process used by the manager. This is only available if [`start()`](#multiprocessing.managers.BaseManager.start) has been used to start the server process. This can be called multiple times. ### Example ```python from multiprocessing.managers import BaseManager # Example of starting a manager class MyManager(BaseManager): pass manager = MyManager(address=('', 50000), authkey=b'abc') manager.start() # Example of connecting to a remote manager # m = BaseManager(address=('127.0.0.1', 5000), authkey=b'abc') # m.connect() ``` ``` -------------------------------- ### billiard.current_process / billiard.active_children Source: https://context7.com/celery/billiard/llms.txt Introspect running processes using current_process() to get the calling process object and active_children() to get a list of live child processes. ```APIDOC ## current_process / active_children ### `billiard.current_process()` / `billiard.active_children()` — introspect running processes `current_process()` returns the `Process` object representing the calling process. `active_children()` returns a list of all live child processes, automatically reaping any that have already finished. ```python import billiard def show_info(): proc = billiard.current_process() print(f"Name: {proc.name}, PID: {proc.pid}, Daemon: {proc.daemon}") procs = [billiard.Process(target=show_info) for _ in range(3)] for p in procs: p.start() import time; time.sleep(0.1) living = billiard.active_children() print(f"Still running: {[p.name for p in living]}") for p in procs: p.join() print(f"Current process: {billiard.current_process().name}") # MainProcess ``` ``` -------------------------------- ### Spawn a function in a child process using billiard.Process Source: https://context7.com/celery/billiard/llms.txt Use billiard.Process to run a function in a separate OS process. Supports fork, spawn, and forkserver start methods. Lifecycle methods like start, join, and terminate are available. ```python import billiard def worker(n): import os print(f"Worker {n}, PID={os.getpid()}") return n * n if __name__ == "__main__": p = billiard.Process(target=worker, args=(42,), name="my-worker", daemon=False) p.start() print(f"Child PID: {p.pid}") p.join(timeout=10) # wait up to 10 seconds print(f"Exit code: {p.exitcode}") # 0 on success print(f"Alive: {p.is_alive()}") # False after join # Subclassing pattern class MyProcess(billiard.Process): def run(self): print(f"Running in PID {self.pid}") mp = MyProcess(daemon=True) mp.start() mp.join() ``` -------------------------------- ### Server: Create Listener and Send Data Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md Sets up a listener on a specified address with authentication and sends various data types to a connected client. ```python from multiprocessing.connection import Listener from array import array address = ('localhost', 6000) # family is deduced to be 'AF_INET' listener = Listener(address, authkey=b'secret password') conn = listener.accept() print('connection accepted from', listener.last_accepted) conn.send([2.25, None, 'junk', float]) conn.send_bytes(b'hello') conn.send_bytes(array('i', [42, 1729])) conn.close() listener.close() ``` -------------------------------- ### Get file descriptor or handle of a connection Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md Returns the file descriptor or handle used by the connection object. ```python fd = conn.fileno() ``` -------------------------------- ### Multiprocessing Entry Point and Argument Handling Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md Sets up the entry point for a multiprocessing script, handling command-line arguments to select between process-based or thread-based multiprocessing. ```python if __name__ == '__main__': multiprocessing.freeze_support() assert len(sys.argv) in (1, 2) if len(sys.argv) == 1 or sys.argv[1] == 'processes': print ' Using processes '.center(79, '-') elif sys.argv[1] == 'threads': print ' Using threads '.center(79, '-') import multiprocessing.dummy as multiprocessing else: print 'Usage:\n\t%s [processes | threads]' % sys.argv[0] raise SystemExit(2) test() ``` -------------------------------- ### multiprocessing.set_executable() Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md Sets the path of the Python interpreter to use when starting a child process. Defaults to sys.executable. This is primarily useful for Windows embedders. ```APIDOC ## multiprocessing.set_executable() ### Description Sets the path of the Python interpreter to use when starting a child process. (By default `sys.executable` is used). Embedders will probably need to do some thing like ```default set_executable(os.path.join(sys.exec_prefix, 'pythonw.exe')) ``` before they can create child processes. (Windows only) ``` -------------------------------- ### Running a Remote Manager Server Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md Sets up a manager server that hosts a shared queue accessible by remote clients. Requires specifying an address and authentication key. ```python >>> from multiprocessing.managers import BaseManager >>> import queue >>> queue = Queue.Queue() >>> class QueueManager(BaseManager): pass >>> QueueManager.register('get_queue', callable=lambda:queue) >>> m = QueueManager(address=('', 50000), authkey='abracadabra') >>> s = m.get_server() >>> s.serve_forever() ``` -------------------------------- ### billiard.Process Source: https://context7.com/celery/billiard/llms.txt The Process class allows you to spawn a function in a child process. It is a drop-in replacement for threading.Thread and supports various start methods. ```APIDOC ## Process ### `billiard.Process` — spawn a function in a child process `Process` is a drop-in replacement for `threading.Thread` that runs code in a separate OS process. It supports `fork`, `spawn`, and `forkserver` start methods and exposes lifecycle methods (`start`, `join`, `terminate`, `is_alive`) along with properties for PID, exit code, daemon status, and name. ```python import billiard def worker(n): import os print(f"Worker {n}, PID={os.getpid()}") return n * n if __name__ == "__main__": p = billiard.Process(target=worker, args=(42,), name="my-worker", daemon=False) p.start() print(f"Child PID: {p.pid}") p.join(timeout=10) # wait up to 10 seconds print(f"Exit code: {p.exitcode}") # 0 on success print(f"Alive: {p.is_alive()}") # False after join # Subclassing pattern class MyProcess(billiard.Process): def run(self): print(f"Running in PID {self.pid}") mp = MyProcess(daemon=True) mp.start() mp.join() ``` ``` -------------------------------- ### Creating a shared Event object Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md Create a shared `threading.Event` object and get a proxy for it. Events can be used to signal between processes that a certain condition has been met. ```python shared_event = manager.Event() ``` -------------------------------- ### Run unit tests with Makefile Source: https://github.com/celery/billiard/blob/main/INSTALL.txt Use the Makefile to run unit tests. This command is typically used on Unix-like systems and can specify the Python version to use. ```shell make test ``` -------------------------------- ### Registering Custom Types with BaseManager Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md Subclass BaseManager and use register() to add custom types or callables. This example registers a MathsClass for use with the manager. ```python from multiprocessing.managers import BaseManager class MathsClass: def add(self, x, y): return x + y def mul(self, x, y): return x * y class MyManager(BaseManager): pass MyManager.register('Maths', MathsClass) if __name__ == '__main__': manager = MyManager() manager.start() maths = manager.Maths() print(maths.add(4, 3)) # prints 7 print(maths.mul(7, 8)) # prints 56 ``` -------------------------------- ### SyncManager.Namespace Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md Creates a shared `Namespace` object and returns a proxy for it. ```APIDOC #### Namespace() Create a shared [`Namespace`](#multiprocessing.managers.SyncManager.Namespace) object and return a proxy for it. ``` -------------------------------- ### multiprocessing.connection.Client Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md Establishes a connection to a listening process using the provided address. ```APIDOC ## Client(address) ### Description Attempt to set up a connection to the listener which is using address *address*, returning a [`Connection`](#multiprocessing.Connection). The type of the connection is determined by *family* argument, but this can generally be omitted since it can usually be inferred from the format of *address*. If *authenticate* is `True` or *authkey* is a string then digest authentication is used. If authentication fails then [`AuthenticationError`](#multiprocessing.connection.AuthenticationError) is raised. ### Parameters - **address**: The address of the listener. - **authenticate** (bool, optional): Whether to use authentication. Defaults to False. - **authkey**: The authentication key. If `None`, `current_process().authkey` is used if `authenticate` is `True`. ``` -------------------------------- ### SyncManager.list Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md Creates a shared `list` object and returns a proxy for it. Can be initialized empty or with a sequence. ```APIDOC #### list() #### list(sequence) Create a shared `list` object and return a proxy for it. ``` -------------------------------- ### Set Process Name with setproctitle Source: https://github.com/celery/billiard/blob/main/CHANGES.txt Sets a useful process name during semaphore cleanup when execv is used, provided the 'setproctitle' module is installed. This helps in identifying processes. ```python import billiard.process import billiard.context # Example usage within a context where setproctitle might be used # This is illustrative and depends on the internal implementation details # of Billiard's semaphore cleanup. ``` -------------------------------- ### SyncManager.Array Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md Creates an array and returns a proxy for it. ```APIDOC #### Array(typecode, sequence) Create an array and return a proxy for it. ``` -------------------------------- ### Using multiprocessing.Queue for Inter-Process Communication Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md Illustrates the use of multiprocessing.Queue for passing data between processes. One process puts items onto the queue, and another gets them, with a timeout for retrieval. ```python def queue_func(queue): for i in range(30): time.sleep(0.5 * random.random()) queue.put(i*i) queue.put('STOP') def test_queue(): q = multiprocessing.Queue() p = multiprocessing.Process(target=queue_func, args=(q,)) p.start() o = None while o != 'STOP': try: o = q.get(timeout=0.3) print o, sys.stdout.flush() except Empty: print 'TIMEOUT' ``` -------------------------------- ### Client: Connect and Receive Data Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md Connects to a server using a specific address and authentication key, then receives and prints data sent by the server. ```python from multiprocessing.connection import Client from array import array address = ('localhost', 6000) conn = Client(address, authkey=b'secret password') print(conn.recv()) # => [2.25, None, 'junk', float] print(conn.recv_bytes()) arr = array('i', [0, 0, 0, 0, 0]) print(conn.recv_bytes_into(arr)) print(arr) ``` -------------------------------- ### run() Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md Method representing the process's activity. Subclasses can override this method. The default implementation invokes the target callable. ```APIDOC ## run() ### Description Method representing the process’s activity. You may override this method in a subclass. The standard `run()` method invokes the callable object passed to the object’s constructor as the target argument, if any, with sequential and keyword arguments taken from the *args* and *kwargs* arguments, respectively. ``` -------------------------------- ### Inter-process Communication using Queue Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md Illustrates how to use a `multiprocessing.Queue` for safe and process-friendly data exchange between processes. Queues must not be instantiated as a side effect of importing a module to avoid deadlocks. ```python from multiprocessing import Process, Queue def f(q): q.put([42, None, 'hello']) if __name__ == '__main__': q = Queue() p = Process(target=f, args=(q,)) p.start() print(q.get()) # prints "[42, None, 'hello']" p.join() ``` -------------------------------- ### Set Python interpreter for child processes Source: https://github.com/celery/billiard/blob/main/Doc/library/multiprocessing.md Sets the path to the Python interpreter used for starting child processes. This is particularly useful for embedders on Windows who might need to specify 'pythonw.exe'. ```python set_executable(os.path.join(sys.exec_prefix, 'pythonw.exe')) ```