[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [stem/master] Investigate an async ainit method
commit ef06783b96ee38230b41cc08c14032d7127f867b
Author: Damian Johnson <atagar@xxxxxxxxxxxxxx>
Date: Tue Jul 7 16:03:11 2020 -0700
Investigate an async ainit method
Our ainit method should be asynchronous, but guess that's not to be.
Documenting the issues we encountered.
---
stem/util/__init__.py | 52 +++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 44 insertions(+), 8 deletions(-)
diff --git a/stem/util/__init__.py b/stem/util/__init__.py
index 5a8f95e0..cddce755 100644
--- a/stem/util/__init__.py
+++ b/stem/util/__init__.py
@@ -199,14 +199,11 @@ class Synchronous(object):
"""
def __init__(self) -> None:
- ainit_func = getattr(self, '__ainit__', None)
-
if Synchronous.is_asyncio_context():
self._loop = asyncio.get_running_loop()
self._loop_thread = None
- if ainit_func:
- ainit_func()
+ self.__ainit__()
else:
self._loop = asyncio.new_event_loop()
self._loop_thread = threading.Thread(
@@ -231,11 +228,50 @@ class Synchronous(object):
if inspect.iscoroutinefunction(func):
setattr(self, method_name, functools.partial(call_async, func))
- if ainit_func:
- async def call_ainit():
- ainit_func()
+ asyncio.run_coroutine_threadsafe(asyncio.coroutine(self.__ainit__)(), self._loop).result()
+
+ def __ainit__(self):
+ """
+ Implicitly called during construction. This method is assured to have an
+ asyncio loop during its execution.
+ """
- asyncio.run_coroutine_threadsafe(call_ainit(), self._loop).result()
+ # This method should be async (so 'await' works), but apparently that
+ # is not possible.
+ #
+ # When our object is constructed our __init__() can be called from a
+ # synchronous or asynchronous context. If synchronous, it's trivial to
+ # run an asynchronous variant of this method because we fully control
+ # the execution of our loop...
+ #
+ # asyncio.run_coroutine_threadsafe(self.__ainit__(), self._loop).result()
+ #
+ # However, when constructed from an asynchronous context the above will
+ # likely hang because our loop is already processing a task (namely,
+ # whatever is constructing us). While we can schedule tasks, we cannot
+ # invoke it during our construction.
+ #
+ # Finally, when this method is simple we could directly invoke it...
+ #
+ # class Synchronous(object):
+ # def __init__(self):
+ # if Synchronous.is_asyncio_context():
+ # try:
+ # self.__ainit__().send(None)
+ # except StopIteration:
+ # pass
+ # else:
+ # asyncio.run_coroutine_threadsafe(self.__ainit__(), self._loop).result()
+ #
+ # async def __ainit__(self):
+ # # asynchronous construction
+ #
+ # However, this breaks if any 'await' suspends our execution. For more
+ # information see...
+ #
+ # https://stackoverflow.com/questions/52783605/how-to-run-a-coroutine-outside-of-an-event-loop/52829325#52829325
+
+ pass
def close(self) -> None:
"""
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits