协程

协程

迭代器

  • 可迭代(Iterable):直接作用于for循环的变量
  • 迭代器(Iterator):不但可以作用于for循环,还可以被next调用
    • list是典型的可迭代对象,但不是迭代器
  • 通过isinstance判断
# isinstance案例
# 判断某个变量是否是一个实例

#判断是否可迭代
from collections import Iterable
from collections import Iterator

ll =[1,2,3,4,5]

print(isinstance(ll, Iterable)) # 可迭代
print(isinstance(ll, Iterator))	# 不是迭代器
  • iterable和iterator可以转换
    • 通过iter函数
# 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
  • 从技术角度讲,协程是一个你可以暂停执行的函数,或者干脆把协程理解成生成器
  • 协程的实现:
    • yield返回
    • send调用
  • 案例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内核
原文地址:https://www.cnblogs.com/rener0424/p/10600922.html