除了async def
和await
语法外,还有一些其它的语法,本章学习异步版的for循环与迭代器,不难理解,普通迭代器是经过__iter__
和__next__
两个特殊方法实现的,以下例。redis
>>> 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
迭代器必须支持__iter__方法;bash
值初始化;网络
返回一个可迭代对象,这个对象能够执行__next__方法,这里A自己就实现了__next__方法,因此返回它自己便可;异步
在每次迭代时调用。async
将__next__()
方法声明为异步函数,要容许await
某些IO操做,除开命名的差异外,几乎是相同的定义,PEP 492中规范说明了如何实现一个异步迭代器:
1. 实现__aiter__()
方法(不须要用async def);
2. __aiter__()
方法必须返回一个支持__anext__()
方法的对象;
3. __anext__()
必须返回迭代器的每一个值,并在结束迭代时抛出StopAsyncIteration
异常。函数
举个例子,好比Redis的key对应的value是一个很大的集合,想迭代这些key的value会出现严重的网络IO,异步迭代器能够这样实现:oop
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())
主程序入口,用于在loop.run_until_complete()方法中调用;学习
使用aioredis库获取异步链接;code
假设每一个key对应的value实例很是大;协程
使用async for循环,关键点是这里的迭代器能够在等待数据时切换任务;
在获得返回值后用协程去处理这个值,假设这个函数也是IO绑定的;
用一个实例来存储redis链接和keys表;
像普通迭代器同样,初始化一些值,这里咱们建立一个迭代器做值,因为这个类也重载了__anext__方法,因此直接返回自身;
__anext__
方法用async def声明;
迭代这个普通的迭代器;
处理普通异常并从新抛出一个异步异常;
这个调用是网络IO,所以用await切换它。
经过以上实现,将能够用一个异步for循环来迭代一些处理网络IO的异步迭代器,好处是能够只用一个事件loop就能处理大量的数据。