summaryrefslogtreecommitdiffstats
path: root/Doc/library
diff options
context:
space:
mode:
authorThomas Grainger <tagrain@gmail.com>2024-12-29 06:22:29 (GMT)
committerGitHub <noreply@github.com>2024-12-29 06:22:29 (GMT)
commitc9159b7436363f0cfbddc3deae1bcf925b5c2d4b (patch)
tree1893396f9781df49d403eedabe5f5d525db36698 /Doc/library
parentf9a5a3a3ef34e63dc197156e9a5f57842859ca04 (diff)
downloadcpython-c9159b7436363f0cfbddc3deae1bcf925b5c2d4b.zip
cpython-c9159b7436363f0cfbddc3deae1bcf925b5c2d4b.tar.gz
cpython-c9159b7436363f0cfbddc3deae1bcf925b5c2d4b.tar.bz2
expand the `asyncio.run_coroutine_threadsafe` recipes (#127576)
Co-authored-by: Kumar Aditya <kumaraditya@python.org>
Diffstat (limited to 'Doc/library')
-rw-r--r--Doc/library/asyncio-task.rst61
1 files changed, 53 insertions, 8 deletions
diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst
index f27e858..4541cf2 100644
--- a/Doc/library/asyncio-task.rst
+++ b/Doc/library/asyncio-task.rst
@@ -1067,14 +1067,59 @@ Scheduling From Other Threads
This function is meant to be called from a different OS thread
than the one where the event loop is running. Example::
- # Create a coroutine
- coro = asyncio.sleep(1, result=3)
-
- # Submit the coroutine to a given loop
- future = asyncio.run_coroutine_threadsafe(coro, loop)
-
- # Wait for the result with an optional timeout argument
- assert future.result(timeout) == 3
+ def in_thread(loop: asyncio.AbstractEventLoop) -> None:
+ # Run some blocking IO
+ pathlib.Path("example.txt").write_text("hello world", encoding="utf8")
+
+ # Create a coroutine
+ coro = asyncio.sleep(1, result=3)
+
+ # Submit the coroutine to a given loop
+ future = asyncio.run_coroutine_threadsafe(coro, loop)
+
+ # Wait for the result with an optional timeout argument
+ assert future.result(timeout=2) == 3
+
+ async def amain() -> None:
+ # Get the running loop
+ loop = asyncio.get_running_loop()
+
+ # Run something in a thread
+ await asyncio.to_thread(in_thread, loop)
+
+ It's also possible to run the other way around. Example::
+
+ @contextlib.contextmanager
+ def loop_in_thread() -> Generator[asyncio.AbstractEventLoop]:
+ loop_fut = concurrent.futures.Future[asyncio.AbstractEventLoop]()
+ stop_event = asyncio.Event()
+
+ async def main() -> None:
+ loop_fut.set_result(asyncio.get_running_loop())
+ await stop_event.wait()
+
+ with concurrent.futures.ThreadPoolExecutor(1) as tpe:
+ complete_fut = tpe.submit(asyncio.run, main())
+ for fut in concurrent.futures.as_completed((loop_fut, complete_fut)):
+ if fut is loop_fut:
+ loop = loop_fut.result()
+ try:
+ yield loop
+ finally:
+ loop.call_soon_threadsafe(stop_event.set)
+ else:
+ fut.result()
+
+ # Create a loop in another thread
+ with loop_in_thread() as loop:
+ # Create a coroutine
+ coro = asyncio.sleep(1, result=3)
+
+ # Submit the coroutine to a given loop
+ future = asyncio.run_coroutine_threadsafe(coro, loop)
+
+ # Wait for the result with an optional timeout argument
+ assert future.result(timeout=2) == 3
If an exception is raised in the coroutine, the returned Future
will be notified. It can also be used to cancel the task in