Python 3.5异步/等待与真实代码examp

2024-04-27 04:39:40 发布

您现在位置:Python中文网/ 问答频道 /正文

我已经阅读了大量关于Python的3.5异步/等待的文章和教程。我不得不说我很困惑,因为有些使用get_event_loop()和run_until_complete(),有些使用sure_future(),有些使用asyncio.wait(),还有一些使用call_soon()。

似乎我有很多选择,但我不知道它们是否完全相同,或者有使用循环的情况,也有使用wait()的情况。

但所有的例子都是用asyncio.sleep()模拟返回可等待对象的真正慢操作。一旦我尝试用这一行代码替换一些真正的代码,整个过程就失败了。上面写的方法和我应该如何运行第三方库之间的区别到底是什么?第三方库还没有准备好进行异步/等待。我确实使用Quandl服务来获取一些股票数据。

 import asyncio
 import quandl

 async def slow_operation(n):
     # await asyncio.sleep(1) # Works because it's await ready.
     await quandl.dataset(n) # Doesn't work because it's not await ready.


 async def main():
     await asyncio.wait([
         slow_operation("SIX/US9884981013EUR4"),
         slow_operation("SIX/US88160R1014EUR4"),
     ])

 # You don't have to use any code for 50 requests/day.
 quandl.ApiConfig.api_key = "MY_SECRET_CODE"

 loop = asyncio.get_event_loop()
 loop.run_until_complete(main())

我希望你能明白我是多么的失落,多么的简单,我想有一个并行运行的事情。


Tags: run代码loopeventasyncioget情况sleep
1条回答
网友
1楼 · 发布于 2024-04-27 04:39:40

如果第三方库与async/await不兼容,显然您不能轻松使用它。有两种情况:

  1. 假设库中的函数是异步的,它会给您一个回调,例如

    def fn(..., clb):
        ...
    

    所以你可以:

    def on_result(...):
        ...
    
    fn(..., on_result)
    

    在这种情况下,可以将这些函数包装到异步协议中,如下所示:

    from asyncio import Future
    
    def wrapper(...):
        future = Future()
        def my_clb(...):
            future.set_result(xyz)
        fn(..., my_clb)
        return future
    

    (异常时使用future.set_exception(exc)

    然后,您可以简单地用await调用某些async函数中的包装器:

    value = await wrapper(...)
    

    注意,await与任何Future对象一起工作。您不必将wrapper声明为async

  2. 如果库中的函数是同步的,那么可以在单独的线程中运行它(可能需要使用一些线程池)。整个代码可能如下所示:

    import asyncio
    import time
    from concurrent.futures import ThreadPoolExecutor
    
    # Initialize 10 threads
    THREAD_POOL = ThreadPoolExecutor(10)
    
    def synchronous_handler(param1, ...):
        # Do something synchronous
        time.sleep(2)
        return "foo"
    
    # Somewhere else
    async def main():
        loop = asyncio.get_event_loop()
        futures = [
            loop.run_in_executor(THREAD_POOL, synchronous_handler, param1, ...),
            loop.run_in_executor(THREAD_POOL, synchronous_handler, param1, ...),
            loop.run_in_executor(THREAD_POOL, synchronous_handler, param1, ...),
        ]
        await asyncio.wait(futures)
        for future in futures:
            print(future.result())
    
    with THREAD_POOL:
        loop = asyncio.get_event_loop()
        loop.run_until_complete(main())
    

如果由于任何原因不能使用线程,那么使用这样的库只会使整个异步代码变得毫无意义。

但是请注意,将同步库与异步库结合使用可能是一个坏主意。你不会得到太多,但你把代码复杂化了很多。

相关问题 更多 >