File tree Expand file tree Collapse file tree 3 files changed +42
-0
lines changed Expand file tree Collapse file tree 3 files changed +42
-0
lines changed Original file line number Diff line number Diff line change @@ -625,16 +625,23 @@ class BaseDefaultEventLoopPolicy(AbstractEventLoopPolicy):
625625
626626 class _Local (threading .local ):
627627 _loop = None
628+ _pid = None
628629 _set_called = False
629630
630631 def __init__ (self ):
631632 self ._local = self ._Local ()
633+ self ._local ._pid = os .getpid ()
632634
633635 def get_event_loop (self ):
634636 """Get the event loop.
635637
636638 This may be None or an instance of EventLoop.
637639 """
640+ if self ._local ._pid != os .getpid ():
641+ # If we detect we're in a child process forked by multiprocessing,
642+ # we reset self._local so that we'll get a new event loop.
643+ self ._local = self ._Local ()
644+
638645 if (self ._local ._loop is None and
639646 not self ._local ._set_called and
640647 isinstance (threading .current_thread (), threading ._MainThread )):
Original file line number Diff line number Diff line change 1313import tempfile
1414import threading
1515import unittest
16+ import multiprocessing
1617from unittest import mock
1718from test import support
1819
@@ -1804,6 +1805,37 @@ def create_watcher(self):
18041805 return asyncio .FastChildWatcher ()
18051806
18061807
1808+ class ForkedProcessTests (unittest .TestCase ):
1809+ def setUp (self ):
1810+ self .parent_loop = asyncio .SelectorEventLoop ()
1811+ asyncio .set_event_loop (self .parent_loop )
1812+ self .ctx = multiprocessing .get_context ("fork" )
1813+
1814+ def tearDown (self ):
1815+ self .parent_loop .close ()
1816+
1817+ def _check_loops_not_equal (self , old_loop ):
1818+ loop = asyncio .get_event_loop ()
1819+ if loop is old_loop :
1820+ raise RuntimeError ("Child process inherited parent's event loop" )
1821+
1822+ try :
1823+ val = loop .run_until_complete (asyncio .sleep (0.05 , result = 42 ))
1824+ if val != 42 :
1825+ raise RuntimeError ("new event loop does not work" )
1826+ finally :
1827+ loop .close ()
1828+
1829+ sys .exit (loop is old_loop )
1830+
1831+ def test_new_loop_in_child (self ):
1832+ p = self .ctx .Process (target = self ._check_loops_not_equal ,
1833+ args = (self .parent_loop ,))
1834+ p .start ()
1835+ p .join ()
1836+ self .assertEqual (p .exitcode , 0 )
1837+
1838+
18071839class PolicyTests (unittest .TestCase ):
18081840
18091841 def create_policy (self ):
Original file line number Diff line number Diff line change 1+ Fix Policy.get_event_loop() to detect fork and return a new loop.
2+
3+ Original patch by Dan O'Reilly.
You can’t perform that action at this time.
0 commit comments