[Python-checkins] (no subject)
Batuhan Taşkaya
webhook-mailer at python.org
Sun Mar 15 15:46:04 EDT 2020
To: python-checkins at python.org
Subject: bpo-39360: Ensure all workers exit when finalizing a multiprocessing
Pool (GH-19009)
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
MIME-Version: 1.0
https://github.com/python/cpython/commit/ac10e0c93218627d1a639db0b7b41714c5f6=
a883
commit: ac10e0c93218627d1a639db0b7b41714c5f6a883
branch: master
author: Batuhan Ta=C5=9Fkaya <47358913+isidentical at users.noreply.github.com>
committer: GitHub <noreply at github.com>
date: 2020-03-15T19:45:56Z
summary:
bpo-39360: Ensure all workers exit when finalizing a multiprocessing Pool (GH=
-19009)
When the pull is not used via the context manager or terminate() is called, t=
here is a system in multiprocessing.util that handles finalization of all poo=
ls via an atexit handler (the Finalize) class. This class registers the _term=
inate_pool handler in the registry of finalizers of the module, and that regi=
stry is called on interpreter exit via _exit_function. The problem is that th=
e "happy" path with the context manager or manual call to finalize() does som=
e extra steps that _terminate_pool does not. The step that is not executed wh=
en the atexit() handler calls _terminate_pool is pinging the _change_notifier=
queue to unblock the maintenance threads.
This commit moves the notification to the _terminate_pool function so is call=
ed from both code paths.
Co-authored-by: Pablo Galindo <Pablogsal at gmail.com>
files:
A Misc/NEWS.d/next/Library/2020-03-15-05-41-05.bpo-39360.cmcU5p.rst
M Lib/multiprocessing/pool.py
M Lib/test/_test_multiprocessing.py
diff --git a/Lib/multiprocessing/pool.py b/Lib/multiprocessing/pool.py
index b223d6aa724bb..41dd923d4f974 100644
--- a/Lib/multiprocessing/pool.py
+++ b/Lib/multiprocessing/pool.py
@@ -651,8 +651,6 @@ def close(self):
def terminate(self):
util.debug('terminating pool')
self._state =3D TERMINATE
- self._worker_handler._state =3D TERMINATE
- self._change_notifier.put(None)
self._terminate()
=20
def join(self):
@@ -682,7 +680,12 @@ def _terminate_pool(cls, taskqueue, inqueue, outqueue, p=
ool, change_notifier,
# this is guaranteed to only be called once
util.debug('finalizing pool')
=20
+ # Notify that the worker_handler state has been changed so the
+ # _handle_workers loop can be unblocked (and exited) in order to
+ # send the finalization sentinel all the workers.
worker_handler._state =3D TERMINATE
+ change_notifier.put(None)
+
task_handler._state =3D TERMINATE
=20
util.debug('helping task handler/workers to finish')
diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessi=
ng.py
index b985d51508cb7..4a87b1761f9ef 100644
--- a/Lib/test/_test_multiprocessing.py
+++ b/Lib/test/_test_multiprocessing.py
@@ -2780,6 +2780,24 @@ def test_pool_worker_lifetime_early_close(self):
for (j, res) in enumerate(results):
self.assertEqual(res.get(), sqr(j))
=20
+ def test_worker_finalization_via_atexit_handler_of_multiprocessing(self):
+ # tests cases against bpo-38744 and bpo-39360
+ cmd =3D '''if 1:
+ from multiprocessing import Pool
+ problem =3D None
+ class A:
+ def __init__(self):
+ self.pool =3D Pool(processes=3D1)
+ def test():
+ global problem
+ problem =3D A()
+ problem.pool.map(float, tuple(range(10)))
+ if __name__ =3D=3D "__main__":
+ test()
+ '''
+ rc, out, err =3D test.support.script_helper.assert_python_ok('-c', c=
md)
+ self.assertEqual(rc, 0)
+
#
# Test of creating a customized manager class
#
diff --git a/Misc/NEWS.d/next/Library/2020-03-15-05-41-05.bpo-39360.cmcU5p.rs=
t b/Misc/NEWS.d/next/Library/2020-03-15-05-41-05.bpo-39360.cmcU5p.rst
new file mode 100644
index 0000000000000..148878886e6ee
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2020-03-15-05-41-05.bpo-39360.cmcU5p.rst
@@ -0,0 +1,4 @@
+Ensure all workers exit when finalizing a :class:`multiprocessing.Pool` impl=
icitly via the module finalization
+handlers of multiprocessing. This fixes a deadlock situation that can be exp=
erienced when the Pool is not
+properly finalized via the context manager or a call to ``multiprocessing.Po=
ol.terminate``. Patch by Batuhan Taskaya
+and Pablo Galindo.
More information about the Python-checkins
mailing list