代码之家  ›  专栏  ›  技术社区  ›  Ramón J Romero y Vigil

在python中对非异步函数使用asyncio?

  •  2
  • Ramón J Romero y Vigil  · 技术社区  · 6 年前

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

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

    我想同时执行这两个查询,而不必添加 async 方法签名或添加修饰符。这些函数根本不应该依赖于异步。

    asyncio 是吗?

    我在找这样的东西:

    #I need an 'asyncWrapper'
    
    results = asyncio.gather(asyncWrapper(queryFoo()), asyncWrapper(queryBar()))
    

    提前感谢您的考虑和回复。

    2 回复  |  直到 6 年前
        1
  •  6
  •   Mikhail Gerasimov    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()
    

    它起作用了。

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

        2
  •  3
  •   Ondrej K.    6 年前

    我想你是在同意之后,希望不要坚持使用 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)
    

    两者兼而有之 queryFoo() queryBar() 并行地,并将其结果收集到一个列表中,按照分配给 results 是的。