Issue44306
This issue tracker has been migrated to GitHub,
and is currently read-only.
For more information,
see the GitHub FAQs in the Python's Developer Guide.
Created on 2021-06-03 22:08 by graingert, last changed 2022-04-11 14:59 by admin.
Messages (3) | |||
---|---|---|---|
msg395054 - (view) | Author: Thomas Grainger (graingert) * | Date: 2021-06-03 22:08 | |
create a asyncio.from_thread shortcut to run async functions from a thread started with asyncio.to_thread ``` 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. ``` |
|||
msg395055 - (view) | Author: Thomas Grainger (graingert) * | Date: 2021-06-03 22:09 | |
"""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)) |
|||
msg415911 - (view) | Author: Andrew Svetlov (asvetlov) * | Date: 2022-03-23 21:09 | |
How is it better than passing the loop instance explicitly? What is the real use case? |
History | |||
---|---|---|---|
Date | User | Action | Args |
2022-04-11 14:59:46 | admin | set | github: 88472 |
2022-03-23 21:09:49 | asvetlov | set | messages: + msg415911 |
2021-06-03 22:09:29 | graingert | set | messages: + msg395055 |
2021-06-03 22:08:45 | graingert | create |