-
-
Notifications
You must be signed in to change notification settings - Fork 31.9k
asyncio.from_thread #88472
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
create a asyncio.from_thread shortcut to run async functions from a thread started with asyncio.to_thread
|
"""High-level support for working with threads in asyncio"""
import functools
import contextvars
from . import events
from . import tasks
__all__ = "to_thread", "from_thread"
class _Local(threading.local):
loop = None
_local = _Local()
def _with_loop(loop, func, /, *args, **kwargs):
_loop.loop = loop
try:
return func(*args, **kwargs)
finally:
_loop.loop = None
async def to_thread(func, /, *args, **kwargs):
"""Asynchronously run function *func* in a separate thread.
Any *args and **kwargs supplied for this function are directly passed
to *func*. Also, the current :class:`contextvars.Context` is propogated,
allowing context variables from the main thread to be accessed in the
separate thread.
Return a coroutine that can be awaited to get the eventual result of *func*.
"""
loop = events.get_running_loop()
ctx = contextvars.copy_context()
func_call = functools.partial(_with_loop, loop, ctx.run, func, *args, **kwargs)
return await loop.run_in_executor(None, func_call)
def _create_task(async_func, /, *args, **kwargs):
return events.create_task(async_func(*args, **kwargs))
async def _with_context(ctx, async_func, /, *args, **kwargs):
return await ctx.run(_create_task, async_func, *args, **kwargs)
def from_thread(async_func, /, *args, **kwargs):
"""Synchronously run function *async_func* in the event loop thread.
Any *args and **kwargs supplied for this function are directly passed
to *func*. Also, the current :class:`contextvars.Context` is propogated,
allowing context variables from the main thread to be accessed in the
separate thread.
Return a concurrent.futures.Future to wait for the result from the event
loop thread.
"""
loop = _loop.loop
if loop is None:
raise RuntimeError(
"asyncio.from_thread can only be run in a thread started by "
"asyncio.to_thread"
)
ctx = contextvars.copy_context()
return tasks.run_coroutine_threadsafe(loop, _with_context(ctx, async_func, *args, **kwargs)) |
How is it better than passing the loop instance explicitly? |
Closing as the use case is unclear. Also one can easily implement something like this by passing loop and |
Let's keep this open. For more about the use case, this seems a design copied from Trio which has both @graingert seems to have a small improvement to |
FWIW, It's too bad that we didn't think of adding the It seems |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: