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.
ThreadPoolExecutor. ThreadPoolExecutor is an Executor subclass that uses a pool of threads to execute calls asynchronously. An Executor subclass that uses a pool of at most max_workers threads to execute calls asynchronously. All threads enqueued to ThreadPoolExecutor will be joined before the interpreter can exit.
The keyword await passes function control back to the event loop. (It suspends the execution of the surrounding coroutine.) If Python encounters an await f() expression in the scope of g() , this is how await tells the event loop, “Suspend execution of g() until whatever I'm waiting on—the result of f() —is returned.
An async function uses the await keyword to denote a coroutine. When using the await keyword, coroutines release the flow of control back to the event loop. To run a coroutine, we need to schedule it on the event loop. After scheduling, coroutines are wrapped in Tasks as a Future object.
asyncio. run(main()) asyncio is a library to write concurrent code using the async/await syntax. asyncio is used as a foundation for multiple Python asynchronous frameworks that provide high-performance network and web-servers, database connection libraries, distributed task queues, etc.
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With