Python 3.5异步/等待实际代码示例

时间:2016-10-10 07:01:42

标签: python asynchronous async-await python-3.5 python-asyncio

我已经阅读了大量有关Python的3.5异步/等待事物的文章和教程。我不得不说我很困惑,因为有些人使用get_event_loop()和run_until_complete(),有些人使用ensure_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())

我希望你明白我的感受是多么的失落,以及我希望并行运行的简单方法。

2 个答案:

答案 0 :(得分:34)

如果第三方库与<?php function wpcf7_dynamic_email_field( $args ) { $dynamic_email = ''; $submission = WPCF7_Submission::get_instance(); $unit_tag = $submission->get_meta( 'wpcf7-f3936-p3933-o1' ); // get the post ID from the unit tag if ( $unit_tag && preg_match( '/^wpcf7-f(\d+)-p(\d+)-o(\d+)$/', $unit_tag, $matches ) ) { $post_id = absint( $matches[2] ); $dynamic_email = get_post_meta( $post_id, 'email', true ); } if ( $dynamic_email ) { $args['recipient'] = str_replace('emailtoreplace@email.com', $dynamic_email, $args['recipient']); } return $args; } add_filter( 'wpcf7_mail_components', 'wpcf7_dynamic_email_field' ); ?> 不兼容,那么显然您无法轻松使用它。有两种情况:

  1. 让我们说库中的函数是异步的,它会给你一个回调,例如

            <activity
                android:name=".MainActivity"
                android:configChanges="${configChanges}"
                android:screenOrientation="${screenOrientation}"
                >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    

    所以你可以这样做:

        defaultConfig {
            manifestPlaceholders = [ screenOrientation:"portrait", configChanges:"orientation"]
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
    
            debug {
                manifestPlaceholders = [ screenOrientation:"unspecified", configChanges:""]
            }
        }
    

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

    async/await

    (在例外情况下使用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)

    请注意async适用于任何await对象。您不必将value = await wrapper(...) 声明为await

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

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

    但请注意,使用带异步的同步库可能是一个坏主意。你赢得了很多,但你的代码很复杂。

答案 1 :(得分:2)

您可以从 here 中查看以下简单的工作示例。顺便说一句,它返回一个值得一读的字符串:-)

import aiohttp
import asyncio

async def fetch(client):
  async with client.get('https://docs.aiohttp.org/en/stable/client_reference.html') as resp:
    assert resp.status == 200
    return await resp.text()

async def main():
  async with aiohttp.ClientSession() as client:
    html = await fetch(client)
    print(html)

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