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. js 数组知识复习

    2.Array类型 2.1 创建数组 两种方式: 1.new Array(); //创建一个空数组 var arr1 = new Array(); //创建一个长度为10的空数组, var arr2 ...

  2. 自己写的页面加载进度条jquery插件

    (function ($) { var progressId = "progress" + Math.round(Math.random() * 100) var progress ...

  3. 【Android】SQLite基本用法(转)

    在Android开发中SQLite起着很重要的作用,网上SQLite的教程有很多很多,不过那些教程大多数都讲得不是很全面.本人总结了一些SQLite的常用的方法,借着论坛的大赛,跟大家分享分享的.一. ...

  4. linux(debian)安装USB无线网卡(tp-link TL-WN725N rtl8188eu )

    1: 台式机家里面不想再走线了. 于是去某东买了个USB无线网卡.tp的WN725N  USB,非常小, 和罗技的优联接收器差不多大. 2:  驱动能自己识别是不指望了,既然是usb网卡,插入USB后 ...

  5. Ubuntu14.04 LTS安装docker

    有以下几种方式: 1. 通过系统自带包安装(可能不是最新版) $ sudo apt-get update $ sudo apt-get install -y docker.io $ sudo ln - ...

  6. jenkins 中 violation使用pylint

    在jenkins中无法打开源码问题: 1. 在 Report Violations的 Source encoding 设置为 项目文件的编码, 如: utf-8.  缺省是 default. 2. 在 ...

  7. springmvc4.2.X fastjson 替换引用配置

    <mvc:annotation-driven> <mvc:message-converters register-defaults="true"> < ...

  8. webapi 初识 net

    1.新建一个webapi 项目. 2.新建筛选器文件,用户在接口执行前后进行特性操作. public class MyActionWebApiAttribute : ActionFilterAttri ...

  9. CSU 1997: Seating Arrangement【构造】

    1997: Seating Arrangement Description Mr. Teacher老师班上一共有n个同学,编号为1到n. 在上课的时候Mr. Teacher要求同学们从左至右按1, 2 ...

  10. Codeforces 785D Anton and School - 2(推公式+乘法原理+组合数学)

    题目链接 Anton and School - 2 对于序列中的任意一个单括号对(), 左括号左边(不含本身)有a个左括号,右括号右边(不含本身有)b个右括号. 那么答案就为 但是这样枚举左右的()的 ...