协程
迭代器
- 可迭代(Iterable):直接作用于for循环的变量
- 迭代器(Iterator):不但可以作用于for循环,还可以被next调用
- 通过isinstance判断
# isinstance案例
# 判断某个变量是否是一个实例
#判断是否可迭代
from collections import Iterable
from collections import Iterator
ll =[1,2,3,4,5]
print(isinstance(ll, Iterable)) # 可迭代
print(isinstance(ll, Iterator)) # 不是迭代器
# iter函数
from collections import Iterable
from collections import Iterator
s = ' i love wcx'
print(isinstance(s, Iterable))
print(isinstance(s, Iterator)) #不是迭代器
s_iter = iter(s)
print(isinstance(s_iter, Iterable))
print(isinstance(s_iter, Iterator)) #转换成迭代器
生成器
- generator:一边循环一边计算下一个元素的机制/算法
- 需要满足三个条件:
- 每次调用都生产出for循环需要的下一个元素
- 如果达到最后一个后,爆出stopIteration异常
- 可以被next函数调用
- 如何生成一个生成器
# 直接使用生成器
L = [x*x for x in range(5)] # 放在中括号中是列表生成器
g = (x*x for x in range(5)) # 放在小括号中就是生成器
# 函数案例
def odd():
print('step 1')
yield 1
print('step 2')
yield 1
print('step 3')
yield 1
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 'Done'
g = fib(5)
for i in range(6):
rst = next(g)
print(rst)
for i in g:
print(i)
协程
- 3.4引入协程,用yield实现
- 3.5引入协程语法
- 实现协程比较好的包有asyncio, tornado, gevent
- 从技术角度讲,协程是一个你可以暂停执行的函数,或者干脆把协程理解成生成器
- 协程的实现:
- 案例1
- 协程的四个状态
- inspect.getgeneratorstate(……)函数确定,该函数会返回下述字符串的一个;
- GEN_CREATED:等待开始执行
- GEN_RUNNING:解释器正在执行
- GEN_SUSPENED:在yield表达式处2暂停
- GEN_CLOSED:执行结束
- next预激(prime)
-案例2
# 案例1
def simple_coroutine():
print('-> start')
x = yield
print('-> recieved', x)
# 主线程
sc = simple_coroutine()
print(1111)
# 可以使用sc.send(None),效果一样
next(sc) #预激
print(2222)
sc.send('zhexiao') # 主线程给协程发一个信号
# 案例2,协程的状态
def simple_coroutine(a):
print('-> start')
b = yield a
print('-> recieved', a, b)
c = yield a + b
print('-> recieved', a, b, c)
# runc
sc = simple_coroutine(5)
aa = next(sc)
print(aa)
bb = sc.send(6)
print(bb)
cc = sc.send(7)
print(cc)
- 协程终止
- 协程中未处理的异常会向上冒泡,传给next函数或send方法的调用方(即触发协程的对象)
- 终止协程的一种方式:发送某个哨符值,让协程退出。内置的None和Ellipsis 等常量经常用作哨符值==
- yield from(相当于一个通道)
- 调用协程为了得到返回值,协程必须正常终止
- 生成器正常终止会发出StopIteration异常,异常对象的value属性保存返回值
- yield from从内部捕获StopIteration异常
- 案例3
- 委派生成器
- 包含yield from表达式的生成器函数
- 委派生成器在yield from表达式处暂停,调用方可以直接把数据发给子生成器
- 子生成器再把产出的值发给调用法
- 子生成器在最后,解释器会抛出StopIteration异常,并且把返回值附加到异常对象上
- 案例4
# 案例3
def gen():
for c in 'AB':
yield c
print(list(gen()))
def gen_new():
yield from 'AB'
print(list(gen_new()))
# 委派生成器
# 案例4
from collections import namedtuple
ResClass = namedtuple('Res', 'count average')
# 子生成器
def averager():
total = 0.0
count = 0
average = None
while True:
term = yield
if term is None:
break
total += term
count += 1
average = total / count
return ResClass(count, average)
# 委派生成器
def grouper(storages, key):
while True:
# 获取average()返回的值
storages[key] = yield from averager()
# 客户端代码
def client():
process_data = {
'boys_2':[39.0, 40.8, 43.2, 40.8, 43.1, 38.6, 41.4, 40.6, 36.3],
'boys_1':[1.38, 1.5, 1.32, 1.25, 1.37, 1.48, 1.25, 1.49, 1.46]
}
storages = {}
for k,v in process_data.items():
# 获得协程
coroutine = grouper(storages, k)
# 预激协程
next(coroutine)
# 发送数据到协程
for dt in v:
coroutine.send(dt)
# 终止协程
coroutine.send(None)
print(storages)
# run
client()
asyncio
- python3.4开始引入标准库当中,内置对异步io的支持
- asuncio本身是一个消息循环
- 步骤:
import threading
# 引入异步io包
import asyncio
# 使用协程
@asyncio.coroutine
def hello():
print('hello world! (%s)' % threading.currentThread())
print('start…… (%s)' % threading.currentThread())
yield from asyncio.sleep(10)
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()
asunc and await
- 为了更好的表示异步io
- python3.5引入
- 让协程代码更简洁
- 使用上,可以简单的进行替换
- 用async替换@asyncio.coroutine
aiohttp
- asyncio实现单线程的并发io,在客户端用处不大
- 在服务器端可以asyncio+coroutine配合,因为http是io操作
- asyncio实现了tcp,udp,ssl等协议
- aiohttp是给予asyncio实现的http框架
- pip install aiohttp安装
# aiohttp案例
concurrent.futures
- python3新增的库
- 类似其他语言的线程池的概念
- 利用multiprocessing实现真正的并行计算
- 核心原理:以子进程的形式,并行运行多个python解释器,从而令python程序可以利用多核CPU来提升执行速度。
由于紫禁城与主解释器相分离,所以他们的全局解释器锁也是相互独立的
每个子进程都能够完整的使用一个CPU内核