We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Concurrency with Threads and asyncio step 19 of 56
Write a Sync Wrapper for Async Code
Libraries often offer a sync version of an async function. Write run_sync,
a general helper that takes any coroutine and runs it from regular code.
async def double(n: int) -> int:
await asyncio.sleep(0)
return n * 2
run_sync(double(21)) # 42 from a plain script, RuntimeError from async code
What to write
def run_sync[T](coro: Coroutine[Any, Any, T]) -> T:
coro is a fresh coroutine that nobody has awaited yet. The [T] after the
name makes the function generic. T stands for the coroutine's result type, so
run_sync(double(21)) has type int.
- Check for a running loop with
asyncio.get_running_loop(). It returns the loop running in the calling thread, or raisesRuntimeErrorif there is none. Put only that call inside thetry, so that aRuntimeErrorraised by the coroutine itself still reaches the caller. - When
get_running_loop()raises, runcorowithasyncio.runand return its result. Each call gets its own new loop, andasyncio.runcloses it at the end, whether the coroutine succeeded or failed. - If the coroutine raises, let the exception propagate with its original type, message and traceback.
- When
get_running_loop()returns a loop, callcoro.close()and then raiseRuntimeError(NESTED_MESSAGE), using the constant from the starter. Close the coroutine without starting a loop or running it. Closing it also silences the warning Python would print later about an unawaited coroutine.
Edge cases
- Only the calling thread counts. In the
other_threadscenario, async code callsrun_syncthroughasyncio.to_thread, which runs it on a worker thread. That thread starts without a loop, so the call succeeds. - Return a result of
0or a negative number as it is.
What the driver reports
Keep solve and the helper coroutines as they are. The scenario input picks
one of five runs:
valuemakes one call, andraisescalls a coroutine that raisesValueError.nestedcallsrun_syncfrom inside a running loop.sequentialmakesrepeatcalls in a row. Only this scenario usesrepeat.other_threadcalls from a worker thread.
Each report has these keys:
outcomeis"ok", or the name of the exception the call raised.messageis the exception's text.valueis the last successful result. It starts at-1and keeps that value when a call fails, or whensequentialgets arepeatof zero or less.traceback_okisTruewhen the traceback still shows_boom, the coroutine that raised.loops_seencounts the loops the helper coroutines ran on. A refused call runs nothing, so it records zero.distinct_loopsisTruewhen every recorded loop is a different object, andall_closedisTruewhen every recorded loop is closed afterwards.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Python reference solution
Sign in to track your attempts toward unlocking the reference solution.