在Python中为非异步函数使用asyncio吗?

Ram*_*gil 3 python python-3.x python-asyncio

假设有一个可以进行各种数据库查询的库:

import time

def queryFoo():
    time.sleep(4)
    return "foo"

def queryBar():
    time.sleep(4)
    return "bar"
Run Code Online (Sandbox Code Playgroud)

我想同时执行这两个查询,而不必添加async到方法签名或添加装饰器。这些功能完全不应该依赖于异步。

在其中利用这些非异步功能的最佳方法是什么asyncio

我正在寻找某种形式的东西:

#I need an 'asyncWrapper'

results = asyncio.gather(asyncWrapper(queryFoo()), asyncWrapper(queryBar()))
Run Code Online (Sandbox Code Playgroud)

预先感谢您的考虑和回应。

Ond*_* K. 10

我想你是在追求并发性,希望不要坚持使用asyncio模块本身,在这种情况下,这个小例子可能会有所帮助:

import asyncio
import time
from concurrent.futures import ThreadPoolExecutor

def queryFoo():
    time.sleep(2)
    return "FOO"

def queryBar():
    time.sleep(4)
    return "BAR"

with ThreadPoolExecutor(max_workers=2) as executor:
    foo = executor.submit(queryFoo)
    bar = executor.submit(queryBar)
    results = [foo.result(), bar.result()]

print(results)
Run Code Online (Sandbox Code Playgroud)

它同时运行queryFoo()queryBar()并行运行,并按照它们在分配给results.


Mik*_*mov 6

如果某个函数在本质上是阻塞的并且不是异步的,那么在asyncio事件循环内运行它的唯一正确方法是使用run_in_executor在线程内运行它:

# Our example blocking functions
import time


def queryFoo():
    time.sleep(3)
    return 'foo'


def queryBar():
    time.sleep(3)
    return 'bar'


# Run them using asyncio
import asyncio
from concurrent.futures import ThreadPoolExecutor


_executor = ThreadPoolExecutor(10)


async def in_thread(func):
    loop = asyncio.get_event_loop()
    return await loop.run_in_executor(_executor, func)


async def main():
    results = await asyncio.gather(
        in_thread(queryFoo), 
        in_thread(queryBar),
    )

    print(results)


if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    try:
        loop.run_until_complete(main())
    finally:
        loop.run_until_complete(loop.shutdown_asyncgens())
        loop.close()
Run Code Online (Sandbox Code Playgroud)

它确实起作用。

但是,如果您要避免使用线程的唯一方法是重写queryFoo/ queryBar本质上是异步的。

  • @EmersonXu *1)* 如果你想将一些异步函数转换为同步,你只需在同步函数中执行 `loop.run_until_complete(asyncfunc())` 即可。但是一旦你这样做了,你就完全摆脱了异步世界:从现在开始,你的所有外部代码都是同步的。*2)* 如果您想将某些同步函数转换为异步函数,请在其他异步函数中使用 `await Loop.run_in_executor(_executor,syncfunc)`。*3)* 如果你想做别的事情,恐怕如果没有可重现的代码示例,我很难理解它。 (2认同)