| 628 | |
| 629 | |
| 630 | class ProcessPoolExecutor(_base.Executor): |
| 631 | def __init__(self, max_workers=None, mp_context=None, |
| 632 | initializer=None, initargs=(), *, max_tasks_per_child=None): |
| 633 | """Initializes a new ProcessPoolExecutor instance. |
| 634 | |
| 635 | Args: |
| 636 | max_workers: The maximum number of processes that can be used to |
| 637 | execute the given calls. If None or not given then as many |
| 638 | worker processes will be created as the machine has processors. |
| 639 | mp_context: A multiprocessing context to launch the workers created |
| 640 | using the multiprocessing.get_context('start method') API. This |
| 641 | object should provide SimpleQueue, Queue and Process. |
| 642 | initializer: A callable used to initialize worker processes. |
| 643 | initargs: A tuple of arguments to pass to the initializer. |
| 644 | max_tasks_per_child: The maximum number of tasks a worker process |
| 645 | can complete before it will exit and be replaced with a fresh |
| 646 | worker process. The default of None means worker process will |
| 647 | live as long as the executor. Requires a non-'fork' mp_context |
| 648 | start method. When given, we default to using 'spawn' if no |
| 649 | mp_context is supplied. |
| 650 | """ |
| 651 | _check_system_limits() |
| 652 | |
| 653 | if max_workers is None: |
| 654 | self._max_workers = os.process_cpu_count() or 1 |
| 655 | if sys.platform == 'win32': |
| 656 | self._max_workers = min(_MAX_WINDOWS_WORKERS, |
| 657 | self._max_workers) |
| 658 | else: |
| 659 | if max_workers <= 0: |
| 660 | raise ValueError("max_workers must be greater than 0") |
| 661 | elif (sys.platform == 'win32' and |
| 662 | max_workers > _MAX_WINDOWS_WORKERS): |
| 663 | raise ValueError( |
| 664 | f"max_workers must be <= {_MAX_WINDOWS_WORKERS}") |
| 665 | |
| 666 | self._max_workers = max_workers |
| 667 | |
| 668 | if mp_context is None: |
| 669 | if max_tasks_per_child is not None: |
| 670 | mp_context = mp.get_context("spawn") |
| 671 | else: |
| 672 | mp_context = mp.get_context() |
| 673 | self._mp_context = mp_context |
| 674 | |
| 675 | # https://github.com/python/cpython/issues/90622 |
| 676 | self._safe_to_dynamically_spawn_children = ( |
| 677 | self._mp_context.get_start_method(allow_none=False) != "fork") |
| 678 | |
| 679 | if initializer is not None and not callable(initializer): |
| 680 | raise TypeError("initializer must be a callable") |
| 681 | self._initializer = initializer |
| 682 | self._initargs = initargs |
| 683 | |
| 684 | if max_tasks_per_child is not None: |
| 685 | if not isinstance(max_tasks_per_child, int): |
| 686 | raise TypeError("max_tasks_per_child must be an integer") |
| 687 | elif max_tasks_per_child <= 0: |