Repository navigation
ProcessPoolExecutor hangs when 1<max_tasks_per_child<num_submitted//max_workers #115634
Copy link
Copy link
Closed
Closed
Copy link
Labels
stdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytopic-multiprocessingtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Description
Bug report
Bug description:
Starting in Python 3.11 when the max_tasks_per_child parameter was introduced, ProcessPoolExecutor hangs when max_tasks_per_child>1 and enough tasks have been submitted to trigger a worker restart.
The following reproducer hangs on a fresh installation of Python 3.11 on Linux.
import os
from concurrent.futures import ProcessPoolExecutor
with ProcessPoolExecutor(1, max_tasks_per_child=2) as exe:
futs = [exe.submit(os.getpid) for _ in range(10)]
for fut in futs:
print(fut.result())Issuing a keyboard interrupt results in the following stack trace:
Traceback (most recent call last):
File "<string>", line 7, in <module>
File "/usr/lib/python3.11/concurrent/futures/_base.py", line 451, in result
self._condition.wait(timeout)
File "/usr/lib/python3.11/threading.py", line 320, in wait
waiter.acquire()
KeyboardInterrupt
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<string>", line 4, in <module>
File "/usr/lib/python3.11/concurrent/futures/_base.py", line 647, in __exit__
self.shutdown(wait=True)
File "/usr/lib/python3.11/concurrent/futures/process.py", line 825, in shutdown
self._executor_manager_thread.join()
File "/usr/lib/python3.11/threading.py", line 1112, in join
self._wait_for_tstate_lock()
File "/usr/lib/python3.11/threading.py", line 1132, in _wait_for_tstate_lock
if lock.acquire(block, timeout):
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
KeyboardInterrupt
Notes:
- Interleaving submissions and result checking does not help.
- Adding a timeout to the
result()calls does not help. - Increasing the pool size does not help, unless it's made large enough to not require any worker restarts.
- Interestingly, setting
max_tasks_per_child=1works great. It never hangs, and a new process correctly used for each task. - It does not hang if
max_tasks_per_childis set high enough so that no worker restarts happen. - I have reproduced this problem in the following test environments:
- On GitHub's default Linux CI environment using Python 3.11.
- On GitHub's default Linux CI environment using Python 3.12.
- On Ubuntu 22.04.3 LTS running under WSL2 using a fresh installation of Python 3.11.
CPython versions tested on:
3.11, 3.12
Operating systems tested on:
Linux
Linked PRs
- gh-115634: Force the process pool to adjust when a process worker exits #115642
- gh-115634: document ProcessPoolExecutor max_tasks_per_child bug #140897
- gh-115634: Fix ProcessPoolExecutor deadlock with max_tasks_per_child #140900
- [3.14] gh-115634: document ProcessPoolExecutor max_tasks_per_child bug (GH-140897) #143302
- [3.13] gh-115634: document ProcessPoolExecutor max_tasks_per_child bug (GH-140897) #143303
- [3.15] gh-115634: Fix ProcessPoolExecutor deadlock with max_tasks_per_child (GH-140900) #152926
- [3.14] gh-115634: Fix ProcessPoolExecutor deadlock with max_tasks_per_child (GH-140900) #152927
- [3.13] gh-115634: Fix ProcessPoolExecutor deadlock with max_tasks_per_child (GH-140900) #152928
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
stdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytopic-multiprocessingtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Activity
[-]ProcessPoolExecutor hangs when 1<max_tasks_per_child<num_submitted[/-][+]ProcessPoolExecutor hangs when 1<max_tasks_per_child<num_submitted//max_workers[/+]gaogaotiantian commentedon Feb 18, 2024
Can't repro this on WSL2 + 3.12/3.11/main. Result:
brianschubert commentedon Feb 18, 2024
Can't reproduce on Linux + 3.12.1/3.11.7/main. I get the same
BrokenProcessPoolas @gaogaotiantian, including whenmax_tasks_per_child=1ormax_tasks_per_child=<very large number>.dalleyg commentedon Feb 18, 2024
Presumably getting
BrokenProcessPoolis also a bug; just a different one. Or am I misunderstanding?Here are the specific Python version I tested on WSL2 + Ubuntu. It was installed with
apt:brianschubert commentedon Feb 18, 2024
@dalleyg
3.11.0rc1is a pre-release version of Python 3.11. Are you able to reproduce this with a "full" release version of Python? Preferably one of the latest minor releases, currently 3.12.2 and 3.11.8.The
BrokenProcessPoollooks like a side effect of your demo script trying to spawn subprocesses at import time while using the "spawn" start method. See "Safe importing of main module" from the multiprocessing docs as described in the error message.dalleyg commentedon Feb 18, 2024
I just downloaded the 3.11.8 tarball from python.org, ran
./configureandmake, moved my~/.localdirectory out of the way, and I still get the same hanging issue.I get the same hanging result on WSL2 + Ubuntu with:
On the other hand, a colleague is seeing the
BrokenProcessPoolexception that both of you are getting on:This makes me wonder if the hanging bug is WSL2 and/or Ubuntu-specific, and the
BrokenProcessPoolbug instead occurs on native Linux systems.Do you recommend that I fork this issue into two?
BrokenProcessPoolproblem.dalleyg commentedon Feb 18, 2024
If I use Docker, I get the
BrokenProcessPoolexception as well:gaogaotiantian commentedon Feb 18, 2024
I failed to repro this on WSL2 + Ubuntu 20.04 so I don't believe WSL is the sufficient trigger.
dalleyg commentedon Feb 18, 2024
Since others can't reproduce my hanging problem, I'll close this issue for now and open a new one for the
BrokenProcessPoolerror.Thanks for the help!
dalleyg commentedon Feb 18, 2024
Okay, I have a reproducer now, so I'm reopening this.
When running the code as a script,
BrokenProcessPoolis the result. When running it withpython -c, hanging is the result. Here's abashreproducer for both using Docker images (note: I'm using some syntax here that's not compatible withzshso be sure to usebash):Here's a snipped version of
broken-script.logthat shows the eager exceptions. The full tracebacks look like the one shown in #115634 (comment).And here's what I see in
broken-inline.log(complete output):20 remaining items
pythongh-115634: document ProcessPoolExecutor max_tasks_per_child bug (…
Mayuresh16 commentedon Apr 28, 2026
@gaogaotiantian @gpshead Can we have a fix for this long-standing bug in the upcoming Python 3.15?
jokester commentedon Apr 29, 2026
before this can be fixed i'm using https://loky.readthedocs.io/en/stable/ for a safer process worker pool
csm10495 commentedon May 30, 2026
Any chance this could be fixed soon? There are a couple PRs that intend to resolve it already.
I just bumped into seeing this issue when trying to use this feature for the first time. Now I'm a bit fearful to use it since I'm not sure if it'll hang.
pythongh-115634: Fix ProcessPoolExecutor deadlock with max_tasks_per_…
gpshead commentedon Jul 3, 2026
yep! I finally picked that PR back up. Updated, just waiting on CI to pass.
gh-115634: Fix ProcessPoolExecutor deadlock with max_tasks_per_child (G…
[3.14] gh-115634: Fix ProcessPoolExecutor deadlock with max_tasks_per…
[3.15] gh-115634: Fix ProcessPoolExecutor deadlock with max_tasks_per…
[3.13] gh-115634: Fix ProcessPoolExecutor deadlock with max_tasks_per…
Fix Text Parser hanging permanently on "Semua file .txt" with many files
fix: replace optimizer workers after every image to avoid a pool hang