Skip to content

Commit 34761bc

Browse files
committed
bpo-29703: asyncio: Fix creating new event loops in child processes.
1 parent 1bea762 commit 34761bc

File tree

4 files changed

+36
-2
lines changed

4 files changed

+36
-2
lines changed

Lib/asyncio/events.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import functools
1313
import inspect
14+
import os
1415
import reprlib
1516
import socket
1617
import subprocess
@@ -611,6 +612,9 @@ def new_event_loop(self):
611612
# A TLS for the running event loop, used by _get_running_loop.
612613
class _RunningLoop(threading.local):
613614
_loop = None
615+
_pid = None
616+
617+
614618
_running_loop = _RunningLoop()
615619

616620

@@ -620,7 +624,8 @@ def _get_running_loop():
620624
This is a low-level function intended to be used by event loops.
621625
This function is thread-specific.
622626
"""
623-
return _running_loop._loop
627+
if _running_loop._pid == os.getpid():
628+
return _running_loop._loop
624629

625630

626631
def _set_running_loop(loop):
@@ -629,6 +634,7 @@ def _set_running_loop(loop):
629634
This is a low-level function intended to be used by event loops.
630635
This function is thread-specific.
631636
"""
637+
_running_loop._pid = os.getpid()
632638
_running_loop._loop = loop
633639

634640

Lib/asyncio/test_utils.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -449,12 +449,15 @@ def new_test_loop(self, gen=None):
449449
self.set_event_loop(loop)
450450
return loop
451451

452+
def unpatch_get_running_loop(self):
453+
events._get_running_loop = self._get_running_loop
454+
452455
def setUp(self):
453456
self._get_running_loop = events._get_running_loop
454457
events._get_running_loop = lambda: None
455458

456459
def tearDown(self):
457-
events._get_running_loop = self._get_running_loop
460+
self.unpatch_get_running_loop()
458461

459462
events.set_event_loop(None)
460463

Lib/test/test_asyncio/test_events.py

+22
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Tests for events.py."""
22

33
import collections.abc
4+
import concurrent.futures
45
import functools
56
import gc
67
import io
@@ -57,6 +58,15 @@ def osx_tiger():
5758
return version < (10, 5)
5859

5960

61+
def _test_get_event_loop_new_process__sub_proc():
62+
async def doit():
63+
return 'hello'
64+
65+
loop = asyncio.new_event_loop()
66+
asyncio.set_event_loop(loop)
67+
return loop.run_until_complete(doit())
68+
69+
6070
ONLYCERT = data_file('ssl_cert.pem')
6171
ONLYKEY = data_file('ssl_key.pem')
6272
SIGNED_CERTFILE = data_file('keycert3.pem')
@@ -2181,6 +2191,18 @@ def tearDown(self):
21812191
asyncio.set_child_watcher(None)
21822192
super().tearDown()
21832193

2194+
def test_get_event_loop_new_process(self):
2195+
async def main():
2196+
pool = concurrent.futures.ProcessPoolExecutor()
2197+
return await self.loop.run_in_executor(
2198+
pool, _test_get_event_loop_new_process__sub_proc)
2199+
2200+
self.unpatch_get_running_loop()
2201+
2202+
self.assertEqual(
2203+
self.loop.run_until_complete(main()),
2204+
'hello')
2205+
21842206
if hasattr(selectors, 'KqueueSelector'):
21852207
class KqueueEventLoopTests(UnixEventLoopTestsMixin,
21862208
SubprocessTestsMixin,

Misc/NEWS

+3
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,9 @@ Library
688688
- Issue #24142: Reading a corrupt config file left configparser in an
689689
invalid state. Original patch by Florian Höch.
690690

691+
- Issue #29703: Fix asyncio to support instantiation of new event loops
692+
in child processes.
693+
691694
Windows
692695
-------
693696

0 commit comments

Comments
 (0)