带有实际代码示例的Python 3.5异步/等待 [英] Python 3.5 async/await with real code example

查看:88
本文介绍了带有实际代码示例的Python 3.5异步/等待的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I've read tons of articles and tutorial about Python's 3.5 async/await thing. I have to say I'm pretty confused, because some use get_event_loop() and run_until_complete(), some use ensure_future(), some use asyncio.wait(), and some use call_soon().

似乎我有很多选择,但是我不知道它们是否完全相同,或者在某些情况下使用循环并且在某些情况下使用wait().

It seems like I have a lot choices, but I have no idea if they are completely identical or there are cases where you use loops and there are cases where you use wait().

但是关键是所有示例都可以与asyncio.sleep()一起使用,模拟真实的慢速操作,该操作会返回一个等待对象.一旦我尝试将该行换成一些实际代码,整个事情就会失败.上面写的方法之间的区别到底是什么,以及我应该如何运行尚未准备好进行异步/等待的第三方库.我确实使用Quandl服务来获取一些库存数据.

But the thing is all examples work with asyncio.sleep() as simulation of real slow operation which returns an awaitable object. Once I try to swap this line for some real code the whole thing fails. What the heck are the differences between approaches written above and how should I run a third-party library which is not ready for async/await. I do use the Quandl service to fetch some stock data.

 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())

希望您能明白我的迷失以及我希望并行运行的简单之处.

I hope you get the point how lost I feel and how simple thing I would like to have running in parallel.

推荐答案

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

If a third-party library is not compatible with async/await then obviously you can't use it easily. There are two cases:

  1. 比方说,库中的函数是异步的,它为您提供了回调,例如

  1. Let's say that the function in the library is asynchronous and it gives you a callback, e.g.

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

因此您可以这样做:

def on_result(...):
    ...

fn(..., on_result)

在这种情况下,您可以将此类函数包装到asyncio协议中,如下所示:

In that case you can wrap such functions into the asyncio protocol like this:

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函数中简单地调用该包装器:

Then you can simply call that wrapper in some async function with await:

value = await wrapper(...)

请注意,await可与任何Future对象一起使用.您不必将wrapper声明为async.

Note that await works with any Future object. You don't have to declare wrapper as async.

如果库中的函数是同步的,则可以在单独的线程中运行它(可能会为此使用一些线程池).整个代码可能看起来像这样:

If the function in the library is synchronous then you can run it in a separate thread (probably you would use some thread pool for that). The whole code may look like this:

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())

如果由于某种原因不能使用线程,那么使用这样的库只会使整个异步代码毫无意义.

If you can't use threads for whatever reason then using such a library simply makes entire asynchronous code pointless.

但是请注意,将同步库与async一起使用可能不是一个好主意.您不会得到太多,但是却使代码复杂了很多.

Note however that using synchronous library with async is probably a bad idea. You won't get much and yet you complicate the code a lot.

这篇关于带有实际代码示例的Python 3.5异步/等待的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆