Reputation: 29916
I wanted to use a ThreadPoolExecutor from a python coroutine, to delegate some blocking network calls to a separate thread. However, running the following code:
from concurrent.futures import ThreadPoolExecutor
import asyncio
def work():
# do some blocking io
pass
async def main():
executor = ThreadPoolExecutor()
await executor.submit(work)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()
causes error:
TypeError: object Future can't be used in 'await' expression
Aren't Future
objects awaitable? Why does it say they aren't?
How can I await
a Future
object returned by executor.submit
?
Python 3.5.0
EDIT
Using executor.submit
is not my decision. This is used internally by several libraries, like requests-futures
. I am searching for a way to interop with those modules from coroutines.
Upvotes: 26
Views: 18068
Reputation: 5163
You should use loop.run_in_executor
:
from concurrent.futures import ThreadPoolExecutor
import asyncio
def work():
# do some blocking io
pass
async def main(loop):
executor = ThreadPoolExecutor()
await loop.run_in_executor(executor, work)
loop = asyncio.get_event_loop()
loop.run_until_complete(main(loop))
loop.close()
EDIT
concurrent.futures.Future
object are different from asyncio.Future
. The asyncio.Future
is intended to be used with event loops and is awaitable, while the former isn't. loop.run_in_executor
provides the necessary interoperability between the two.
EDIT #2
Using executor.submit is not my decision. This is used internally by several libraries, like requests-futures. I am searching for a way to interop with those modules from coroutines.
EDIT #3
Since python 3.5 (docs), you can use asyncio.wrap_future(future, *, loop=None)
to convert a concurrent.futures.Future
to a asyncio.Future
.
Upvotes: 39