Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Await Future from Executor: Future can't be used in 'await' expression

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.

like image 632
Tamas Hegedus Avatar asked Dec 20 '15 00:12

Tamas Hegedus


People also ask

Is ThreadPoolExecutor asynchronous?

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.

How does await work in Python?

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.

How do I use async await in Python?

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.

What is Asyncio run?

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.


1 Answers

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.

like image 193
Jashandeep Sohi Avatar answered Sep 19 '22 17:09

Jashandeep Sohi