Async Iterators: async for

除了async defawait语法外,还有一些其它的语法,本章学习异步版的for循环与迭代器,不难理解,普通迭代器是通过__iter____next__两个特殊方法实现的,如下例。

>>> class A:
...     def __iter__(self):    # 1
...             self.x = 0     # 2
...             return self    # 3
...     def __next__(self):    # 4
...             if self.x > 2:
...                     raise StopIteration
...             else:
...                     self.x += 1
...                     return self.x
>>> for i in A():
...     print(i)
...
1
2
3
  1. 迭代器必须支持__iter__方法;

  2. 值初始化;

  3. 返回一个可迭代对象,这个对象可以执行__next__方法,这里A本身就实现了__next__方法,所以返回它本身即可;

  4. 在每次迭代时调用。


__next__()方法声明为异步函数,要允许await某些IO操作,除开命名的差别外,几乎是相同的定义,PEP 492中规范说明了如何实现一个异步迭代器:
1. 实现__aiter__()方法(不需要用async def);
2. __aiter__()方法必须返回一个支持__anext__()方法的对象;
3. __anext__()必须返回迭代器的每个值,并在结束迭代时抛出StopAsyncIteration异常。

举个例子,比如Redis的key对应的value是一个很大的集合,想迭代这些key的value会出现严重的网络IO,异步迭代器可以这样实现:

import asyncio
from aioredis import create_redis

async def main():   # 1
    redis = await create_redis(('localhost', 6379))    # 2
    keys = ['America', 'Africa', 'Europe', 'Asia']  # 3

    async for value in OneAtTime(redis, keys):  # 4
        await process(value)    # 5

class OneAtTime:
    def __init__(self, redis, keys):    # 6
        self.redis = redis
        self.keys = keys
    def __aiter__(self):    # 7
        self.ikeys = iter(self.keys)
        return self
    async def __anext__(self):  # 8
        try:
            k = next(self.ikeys)    # 9
        except StopIteration:   # 10
            raise StopAsyncIteration
        value = await redis.get(k)  # 11
        return value

asyncio.get_event_loop().run_until_complete(main())
  1. 主程序入口,用于在loop.run_until_complete()方法中调用;

  2. 使用aioredis库获取异步连接;

  3. 假设每个key对应的value实例非常大;

  4. 使用async for循环,关键点是这里的迭代器可以在等待数据时切换任务;

  5. 在得到返回值后用协程去处理这个值,假设这个函数也是IO绑定的;

  6. 用一个实例来存储redis连接和keys表;

  7. 像普通迭代器一样,初始化一些值,这里我们创建一个迭代器作值,由于这个类也重载了__anext__方法,所以直接返回自身;

  8. __anext__方法用async def声明;

  9. 迭代这个普通的迭代器;

  10. 处理普通异常并重新抛出一个异步异常;

  11. 这个调用是网络IO,因此用await切换它。


通过以上实现,将可以用一个异步for循环来迭代一些处理网络IO的异步迭代器,好处是可以只用一个事件loop就能处理大量的数据。

深入Asyncio(八)异步迭代器的更多相关文章

  1. 一文说通C#中的异步迭代器

    今天来写写C#中的异步迭代器 - 机制.概念和一些好用的特性   迭代器的概念 迭代器的概念在C#中出现的比较早,很多人可能已经比较熟悉了. 通常迭代器会用在一些特定的场景中. 举个例子:有一个for ...

  2. C# 8 中的异步迭代器 IAsyncEnumerable<T> 解析

    异步编程已经流行很多年了,.NET 引入的 async 和 await 关键词让异步编程更具有可读性,但有一个遗憾,在 C# 8 之前都不能使用异步的方式处理数据流,直到 C# 8 引入的 IAsyn ...

  3. 在Python中使用asyncio进行异步编程

    对于来自JavaScript编码者来说,异步编程不是什么新东西,但对于Python开发者来说,async函数和future(类似JS的promise)可不是那么容易能理解的. Concurrency ...

  4. Python使用asyncio+aiohttp异步爬取猫眼电影专业版

    asyncio是从pytohn3.4开始添加到标准库中的一个强大的异步并发库,可以很好地解决python中高并发的问题,入门学习可以参考官方文档 并发访问能极大的提高爬虫的性能,但是requests访 ...

  5. asyncio之异步上下文管理器

    异步上下文管理器 前面文章我们提到了上下文管理器,但是这个上下文管理器只适用于同步代码,不能用于异步代码(async def形式),不过不用担心今天我们就来讨论在异步中如何使用上下文管理器. 特别提醒 ...

  6. python基础(八)-迭代器与生成器

    一.迭代器 li=[1,2,3] f=li.__iter__() print(f) print(f.__next__()) print(f.__next__()) print(f.__next__() ...

  7. python基础(八)生成器,迭代器,装饰器,递归

    生成器 在函数中使用yield关键字就会将一个普通的函数变成一个生成器(generator),普通的函数只能使用return来退出函数,而不执行return之后的代码.而生成器可以使用调用一个next ...

  8. Python复习笔记(八)迭代器和生成器和协程

    1. 迭代器 1.1 可迭代对象 判断xxx_obj是否可以迭代 在第1步成立的前提下,调用 iter 函数得到 xxx_obj 对象的 __iter__ 方法的返回值 __iter__ 方法的返回值 ...

  9. JDK7新特性<八>异步io/AIO

    概述 JDK7引入了Asynchronous I/O.I/O编程中,常用到两种模式:Reactor 和 Proactor.Reactor就是Java的NIO.当有事件触发时,我们得到通知,进行相应的处 ...

随机推荐

  1. 【XPButton类】美化MFC button (转)

    从网上找到别人写的一个XPButton类,利用XPButton类实现XP风格的按钮.百度一下即可找到这个类,接下来具体的步骤如下: 1.创建基于对话框的MFC工程假设命名为:XPButtonTest, ...

  2. sublime text3中成功使用bootstrap3

    在视图这里卡了挺久的,一直是自己在研究.其实自己有一个坏毛病,遇到问题,在网上搜集下找不到便寻求帮助(大多数是求助无效果,因为自己也没搞懂), 这时候自己就会懈怠一会,然后隔一两天心血起伏后便又继续干 ...

  3. hdu 4994(博弈)

    Revenge of Nim Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  4. 关于webpack的cdn配置

    在webpack中活用cdn可以大幅度减少打包文件的体积,配置方法也非常简单. 首先现在入口html文件(index.html)里引入相应cdn连接,然后配置webpack: module.expor ...

  5. 转载:html+js实现只允许输入两位小数的输入框

    JS代码: <script language="JavaScript" type="text/javascript"> function clear ...

  6. http系列--HTTP2.0新特性:二进制传输,多路复用,Haeder压缩,服务端push,QUIC协议

    一.前言 HTTP 2.0 相比于 HTTP 1.X,可以说是大幅度提高了 web 的性能. 在 HTTP 1.X 中,为了性能考虑,我们会引入雪碧图.将小图内联.使用多个域名等等的方式.这一切都是因 ...

  7. JLOI2018 日志

    JLOI2018 今年有幸参加吉林省的省选,考过之后在这里写一下总结和感受. DAY1: t1(chess):首先看到题目,第一想法是暴力,上来直接写了暴力,枚举所有的情况,再在这些情况里找到差值最大 ...

  8. 屏蔽国内广告的hosts

    源码:https://github.com/easonjim/blackhosts bug提交:https://github.com/easonjim/blackhosts/issues

  9. Docker镜像原理和最佳实践

    https://yq.aliyun.com/articles/68477 https://yq.aliyun.com/articles/57126  DockerCon 2016 深度解读: Dock ...

  10. 【spring cloud】对接口调用者提供API使用的安全验证微服务【这里仅通过代码展示一种设计思想】【后续可以加入redis限流的功能,某段时间某个IP可以访问API几次】

    场景: 公司的微服务集群,有些API 会对外提供接口,供其他厂商进行调用.这些公开的API接口,由一个OpenAPI微服务统一提供给大家. 那么所有的调用者在调用公开API接口的时候,需要验证是否有权 ...