asyncio: stop using get_event_loop(). introduce ~singleton loop.
asyncio.get_event_loop() became deprecated in python3.10. (see https://github.com/python/cpython/issues/83710) ``` .../electrum/electrum/daemon.py:470: DeprecationWarning: There is no current event loop self.asyncio_loop = asyncio.get_event_loop() .../electrum/electrum/network.py:276: DeprecationWarning: There is no current event loop self.asyncio_loop = asyncio.get_event_loop() ``` Also, according to that thread, "set_event_loop() [... is] not deprecated by oversight". So, we stop using get_event_loop() and set_event_loop() in our own code. Note that libraries we use (such as the stdlib for python <3.10), might call get_event_loop, which then relies on us having called set_event_loop e.g. for the GUI thread. To work around this, a custom event loop policy providing a get_event_loop implementation is used. Previously, we have been using a single asyncio event loop, created with util.create_and_start_event_loop, and code in many places got a reference to this loop using asyncio.get_event_loop(). Now, we still use a single asyncio event loop, but it is now stored as a global in util._asyncio_event_loop (access with util.get_asyncio_loop()). I believe these changes also fix https://github.com/spesmilo/electrum/issues/5376
This commit is contained in:
@@ -273,7 +273,7 @@ class Network(Logger, NetworkRetryManager[ServerAddr]):
|
||||
init_retry_delay_urgent=1,
|
||||
)
|
||||
|
||||
self.asyncio_loop = asyncio.get_event_loop()
|
||||
self.asyncio_loop = util.get_asyncio_loop()
|
||||
assert self.asyncio_loop.is_running(), "event loop not running"
|
||||
|
||||
assert isinstance(config, SimpleConfig), f"config should be a SimpleConfig instead of {type(config)}"
|
||||
@@ -381,9 +381,11 @@ class Network(Logger, NetworkRetryManager[ServerAddr]):
|
||||
self.channel_db = None
|
||||
self.path_finder = None
|
||||
|
||||
def run_from_another_thread(self, coro, *, timeout=None):
|
||||
assert util.get_running_loop() != self.asyncio_loop, 'must not be called from network thread'
|
||||
fut = asyncio.run_coroutine_threadsafe(coro, self.asyncio_loop)
|
||||
@classmethod
|
||||
def run_from_another_thread(cls, coro, *, timeout=None):
|
||||
loop = util.get_asyncio_loop()
|
||||
assert util.get_running_loop() != loop, 'must not be called from asyncio thread'
|
||||
fut = asyncio.run_coroutine_threadsafe(coro, loop)
|
||||
return fut.result(timeout)
|
||||
|
||||
@staticmethod
|
||||
@@ -1321,7 +1323,7 @@ class Network(Logger, NetworkRetryManager[ServerAddr]):
|
||||
assert util.get_running_loop() != network.asyncio_loop
|
||||
loop = network.asyncio_loop
|
||||
else:
|
||||
loop = asyncio.get_event_loop()
|
||||
loop = util.get_asyncio_loop()
|
||||
coro = asyncio.run_coroutine_threadsafe(cls._send_http_on_proxy(method, url, **kwargs), loop)
|
||||
# note: _send_http_on_proxy has its own timeout, so no timeout here:
|
||||
return coro.result()
|
||||
|
||||
Reference in New Issue
Block a user