asyncio: clarify strong refs for run_coroutine_threadsafe
We added some code in 0b3a283586
to explicitly hold strong refs for all tasks/futures. At the time I was uncertain if that also solves
GC issues with asyncio.run_coroutine_threadsafe.
ref https://github.com/spesmilo/electrum/pull/9608#issuecomment-2703681663
Looks like it does. run_coroutine_threadsafe *is* going through the custom task factory.
See the unit test.
The somewhat confusing thing is that we need a few event loop iterations for the task factory to run,
due to how run_coroutine_threadsafe is implemented. And also, the task that we will hold as strong ref
in the global set is not the concurrent.futures.Future that run_coroutine_threadsafe returns.
So this commit simply "fixes" the unit test so that it showcases this, and removes related, older, plumbing
from util.py that we now know is no longer needed because of this.
This commit is contained in:
@@ -482,20 +482,30 @@ class TestUtil(ElectrumTestCase):
|
||||
async def foo():
|
||||
await evt.wait()
|
||||
|
||||
# spawn tasks
|
||||
fut = asyncio.ensure_future(foo())
|
||||
self.assertTrue(fut in util._running_asyncio_tasks)
|
||||
fut = asyncio.create_task(foo())
|
||||
self.assertTrue(fut in util._running_asyncio_tasks)
|
||||
fut = loop.create_task(foo())
|
||||
self.assertTrue(fut in util._running_asyncio_tasks)
|
||||
#fut = asyncio.run_coroutine_threadsafe(foobar(), loop=loop)
|
||||
fut = asyncio.run_coroutine_threadsafe(foo(), loop=loop)
|
||||
# run_coroutine_threadsafe will create a different (chained) future in _running_asyncio_tasks
|
||||
# (which btw will only happen a few event loop iterations later)
|
||||
#self.assertTrue(fut in util._running_asyncio_tasks)
|
||||
|
||||
# wait a few event loop iterations
|
||||
for _ in range(10):
|
||||
await asyncio.sleep(0)
|
||||
# we should have stored one ref for each above.
|
||||
# (though what if test framework is doing stuff ~concurrently?)
|
||||
self.assertEqual(3, len(util._running_asyncio_tasks))
|
||||
self.assertEqual(4, len(util._running_asyncio_tasks))
|
||||
for task in util._running_asyncio_tasks:
|
||||
self.assertEqual(foo().__qualname__, task.get_coro().__qualname__)
|
||||
# let tasks finish
|
||||
evt.set()
|
||||
for _ in range(10): # wait a few event loop iterations
|
||||
# wait a few event loop iterations
|
||||
for _ in range(10):
|
||||
await asyncio.sleep(0)
|
||||
# refs should be cleaned up by now:
|
||||
self.assertEqual(0, len(util._running_asyncio_tasks))
|
||||
|
||||
Reference in New Issue
Block a user