Currently asyncio.futures.Future.set_result will result in any callbacks being scheduled using loop.call_soon instead of loop.call_soon_threadsafe. However in situations where the future's result is set from a different thread, the loop might not wake up as a result of this if it is currently sleeping. def compute_something(...): loop = asyncio.get_event_loop() future = loop.create_future() manager.run_computation(future, ...) # add the computation to a thread that is running it return future async def compute_stuff(): result = await compute_something(...) loop = asyncio.get_event_loop() loop.run_until_complete(compute stuff()) loop.close() The reasoning behind it is after yielding the Future object, the ready list of the event loop is empty so when waiting for selectors the timeout value is None and it just waits. When the other thread calls set_result, the loop ready list will get updated, but it's still waiting on selectors. The other thread could call future._loop.call_soon_threadsafe(future.set_result, ...), which writes some bytes to a socket in order to wake the even loop. I'm aware there are other ways to do things like this (queues, executors, etc). It just seems that, regardless of any method used, the code holding the future with the purpose of setting a result on it should be able to be blind to other implementation details. future.set_result should be all it needs to know to call even if from another thread, or if not, a method like future.set_result_threadsafe, which would hide the details of the loop.call_soon/call_soon_threadsafe