首页 文章

Python asyncio,可以等待/产生整个myFunction()

提问于
浏览
2

我编写了一个对象库,其中很多都是HTTP / IO调用 . 由于不断增加的开销,我一直在考虑转移到asyncio,但我不想重写底层代码 .

我一直希望在我的代码中包含asyncio,以便异步执行函数,而不用await / yield替换所有深度/低级代码 .

我开始尝试以下方法:

async def my_function1(some_object, some_params):
      #Lots of existing code which uses existing objects
      #No await statements
      return output_data

async def my_function2():
      #Does more stuff

while True:
    loop = asyncio.get_event_loop()
    tasks = my_function(some_object, some_params), my_function2()
    output_data = loop.run_until_complete(asyncio.gather(*tasks))
    print(output_data)

我很快意识到,当这段代码运行时,没有任何实际异步发生,函数同步完成 . 我对异步编程很新,但我认为这是因为 neither of my functions are using the keyword await or yield 因此这些函数不是cooroutine,并且不会产生,因此不提供转移到不同cooroutine的机会 . 如果我错了,请纠正我 .

我的问题是,是否可以在asyncio await关键字中包装复杂的函数(在它们深入的内部进行HTTP / IO调用),例如

async def my_function():
    print("Welcome to my function")
    data = await bigSlowFunction()

UPDATE - Following Karlson's Answer

接下来,感谢Karlsons接受了回答,我使用了以下代码,它运行良好:

from concurrent.futures import ThreadPoolExecutor
import time    

#Some vars
a_var_1 = 0
a_var_2 = 10

pool = ThreadPoolExecutor(3)

future = pool.submit(my_big_function, object, a_var_1, a_var_2)
while not future.done() :
    print("Waiting for future...")
    time.sleep(0.01)
print("Future done")
print(future.result())

这非常好用,并且future.done()/ sleep循环让您了解通过异步获得多少CPU周期 .

1 回答

  • 3

    简短的回答是,如果没有明确标记代码中可以将控制权传递回事件循环的点,则无法获得asyncio的好处 . 这可以通过将IO重函数转换为协同程序来完成,就像您假设的那样 .

    在不更改现有代码的情况下,您可以使用greenlets实现目标(请查看eventletgevent) .

    另一种可能性是利用Python的Future implementation包装并将对已经编写的函数的调用传递给某些ThreadPoolExecutor并产生最终的Future . 请注意,这包含了多线程编程的所有注意事项 .

    有点像

    from concurrent.futures import ThreadPoolExecutor
    
    from thinair import big_slow_function
    
    executor = ThreadPoolExecutor(max_workers=5)
    
    async def big_slow_coroutine():
        await executor.submit(big_slow_function)
    

相关问题