简体   繁体   中英

asyncio: how to combine sync code without forcing full exposure to asyncio

It seems that python's asyncio is an all-or-nothing kind of deal. Specifically it seems to force full call stack to be async-aware.

Here is an example:

Let's assume that there is an algorithm implemented by function a() .
That algorithm calls function b() .

def a(b):
  for i in ...:
    # do smth...
    res = b()
    # do smth more ...

Now let's assume that function b() might be implemented differently in different environments and one might want to call a() inside an async event loop (with loop.call_soon() ) with b() calling some asyncio-aware code:

def b():
   await .... # this forces b() to be declared async.

Using existing event loop seems to be explicitly prohibited... So, are there methods to implement this functionality without forcing the full stack ( a() and b() ) to be explicitly defined as async coroutines?

Although taken at face value asyncio is an all-or-nothing deal, there are still two escape hatches that can help when dealing with legacy or heterogenous environment:

  • Within asyncio, you can await loop.run_in_executor(callable, args...) to evaluate sync code in another thread, suspending the current coroutine until the result is ready.

  • Outside asyncio, you can use asyncio.run_coroutine_threadsafe() to submit a coroutine to an event loop running in another thread. It immediately returns returns a concurrent.futures future which has a blocking result() method that blocks the current thread without adversely affecting the event loop. (The use of run_coroutine_threadsafe requires starting an event loop in a dedicated thread beforehand.)

With those two tools at your disposal, it is not that hard to mix asyncio and classic synchronous code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM