协程
- 参考资料
迭代器
- 可迭代(Iterable):直接作用于for循环变量
- 迭代器(Iterator):不但可以作用于for循环,还可以被next调用
- list是典型的可迭代对象,但不是迭代器
- 通过isinstance判断是否是迭代器
- iterable和iteration可以转换
-
通过iter函数
#isinstance案例 #判断某一个变量是否是一个实例 #判断是否可迭代 from collections import Iterable l1 = [1,2,3,4,5] print(isinstance(l1,Iterable)) from collections import Iterator print(isinstance(l1,Iterator))
-
生成器
- generator:一边循环一边计算元素的机制/算法
- 须要满足三个条件:
- 每次调用都生产出for循环需要的下一个元素
- 如果达到最后一个后,爆出StopIteration异常
- 可以被next函数屌用
- 如何生成一个生成器
-
直接使用
-
如果函数中包含yield,则这个函数叫生成器
-
next调用函数,遇到yield返回
#生成器案例 #在函数odd中,yield负责返回 def odd(): print("step 1") yield 1 print("step 2") yield 2 print("step 3") yield 3 #odd()是调用函数生成器 g = odd() one = next(g) print(one) two = next(g) print(two) three = next(g) print(three) #裴波那契数列的生成器写法 def fib(max): n,a,b = 0,0,1 while n < max: yield b a,b = b, a+b n+= 1 #需要注意的是,爆出异常的返回值是return的返回值 return 'Done' ge = fib(5) #生成器的典型用法是在for中使用,比较常用的典型生成器就是range for i in ge: print(i)
-
协程
-
历史历程
- 3.4引入协程,用yield实现
- 3.5引入协程语法
- 实现的协程比较好的包有asyncio, tornado, gevent
-
定义:协程 是为非抢占式多任务产生子程序的计算机程序组件,协程允许不同入口点在不同位置暂停或开始执行程序”。
-
从技术角度讲,协程就是一个你可以暂停执行的函数,或者干脆把协程理解成生成器
-
协程的实现:
- yield返回
- send调用
-
协程的四个状态
- inspect.getgeneratorstate(…) 函数确定,该函数会返回下述字符串中的一个:
- GEN_CREATED:等待开始执行
- GEN_RUNNING:解释器正在执行
- GEN_SUSPENED:在yield表达式处暂停
- GEN_CLOSED:执行结束
- next预激(prime)
- 代码案例v2
-
协程终止
- 协程中未处理的异常会向上冒泡,传给 next 函数或 send 方法的调用方(即触发协程的对象)
- 止协程的一种方式:发送某个哨符值,让协程退出。内置的 None 和Ellipsis 等常量经常用作哨符值==。
-
yield from
- 调用协程为了得到返回值,协程必须正常终止
- 生成器正常终止会发出StopIteration异常,异常对象的vlaue属性保存返回值
- yield from从内部捕获StopIteration异常
- 案例v03
- 委派生成器
-
包含yield from表达式的生成器函数
-
委派生成器在yield from表达式出暂停,调用方可以直接把数据发给自生成器
-
子生成器在把产出的值发给调用放
-
自生成器在最后,解释器会抛出StopIteration,并且把返回值附加到异常对象上
-
案例v04
#协程代码案例1 def simple_coroutine(): print('->start') x = yield print('->recived',x) #主线程 sc = simple_coroutine() print(1111) next(sc)#预激 print(2222) sc.send('zhexiao') #案例v2, 协程的状态 def simple_coroutine(a): print('->start') b = yield a print('->recived',a,b) c = yield a+b print('->',a,b,c) # runc sc = simple_coroutine(5) aa = next(sc) pirnt(aa) bb = sc.send(6) print(bb) cc = sc.send(7) print(cc) #案例v03 def gen(): for c in 'AB' yield c #list直接用生成器作为参数 print(list(gen())) def gen_new(): yield from 'AB' print(list(gen_new))) #案例v04,委派生成器 from collections import namedtuple ResClass = namedtuple('Res','count average') #子生成器 def averager(): total = 0.0 count = 0 average = None while True: term = yield #None是哨兵值 if term is None: break total +=term count +=1 average = total / count return ResClass(count, average) #委派生成器 def grounper(storage,key): while True: #获取average()返回值 storage[key] = yield from averager() def client(): process_data = { 'boy_2' :[39.0,40.8,......], 'boy_1':[1.38,1.5,1.32,.......] } storage = {} for k,v in process_data.items(): #获取协程 coroutine = grouper(storages,k) #预激协程 next(coroutine) #发送数据到协程 for dt in v: coroutine.send(None) print(storages) #run client()
-
asyncio
- python3.4开始引入标准库当中,内置对异步io的支持
- asyncio本身是一个消息循环
- 步骤:
-
创建消息循环
-
把协程导入
-
关闭
import threading import asyncio #使用协程 @asyncio.coroutine def hello(): print('Hello world!(%s)'%threading.currentThread()) print('Start....(%s)'%threading.currentThread()) yield from asyncio.sleep(5) print(‘Done....(%s)'%threading.currentThread()) print('Hello again!(%s)'%threading.currentThread()) #启动消息循环 loop = asyncio.get_event_loop() #定义任务 tasks = [hello(),hello()] #asyncio使用wait等待task执行完毕 loop.run_until_complete(asyncio.wait(tasks)) #关闭消息循环 loop.close()
-
async and await
- 为了更好地表示异步IO
-
- python3.5引入
- 让协程代码更简洁
- 使用上,可以简单的进行替换
- 用async替换@asyncio.coroutine
- await 替换 yield from
aiohttp
- asyncio实现单线程的并io,在客户端用处不大
- 在服务器可以asyncio+coroutine配合,因为http是io操作
- asyncio实现了tcp,udp,ssl等协议
- aiohttp是给予asyncio实现的http框架
- pip install aiohttp安装
concurrent.futures
- python3新增的库
- 类似于其他语言的线程池的概念
- 利用multiprocessing实现真正的并行计算
- 核心原理:以子进程的形式运行多个python解释器,从而令python程序可以利用多核CPU来提升执行速度。由于子进程与与主解释器相分离,所以她们的全局解释器锁也是相互独立的。每个子进程都能完整的使用一个CPU内核
- concurrent.futures.Executor
- threadPoolExecutor
- ProcessPoolExecutor
- 执行的时候需要自行选择
- submit(fn,args,kwargs)
- fn: 异步执行函数
- args,kwargs函数
current中的map函数
- map(fn,*iterables,timeout = None)
- 跟map函数类似
- 函数需要异步执行
- timeout:超时时间
- map跟submit使用一个就行