python --- 协程

协程

1、参考资料

2、迭代器

  • 可迭代(Iterable):直接作用于for循环的变量
  • 迭代器(iterator):不但可以作用于for循环,还可以被next调用
    • list是典型的可迭代对象,但不是迭代器
      #可迭代
      l = [i for i in range(10)]
      for idx in l:
          print(idx)
      #l是可迭代对象,但不是迭代器
      for i in range(5):
          print(i)
      #range是一个迭代器
  • 通过isinstance判断
    • 判断某个变量是否是一个实例
      from collections import Iterable,Iterator
      import collections
      ll = [1,1,23,4,5]
      
      print(isinstance(ll,Iterable))
      print(isinstance(ll,Iterator))
  • 可以通过iter函数进行转换
    from collections import Iterable,Iterator
    import collections
    ll = [1,1,23,4,5]
    print(isinstance(ll,Iterable))
    print(isinstance(ll,Iterator))
    s_iter = iter(ll)
    print(isinstance(s_iter,Iterable))
    print(isinstance(s_iter,Iterator))

3、生成器

  • generator:一边循环一遍计算下一个元素的机制/算法
  • 需要满足三个条件
    • 1、每次调用都生产出for循环需要的下一个元素
    • 2、如果达到最后一个,爆出StopIteration异常
    • 3、可以被next函数调用
  • 如何制作一个生成器
    • 1、直接使用
      l = [x*x for x in range(5)]
      #放在中括号里就是列表生成器
      g = (x*x for x in range(5)
      #放在小括号里就是生成器
      print(type(l))
      print(type(g))
    • 2、如果函数中包含yield,则这个函数就叫生成器
      • next调用函数,遇到yield返回
      def odd():    
      	print('Step 1')    
      	yield 1    
      	print('Step 2')    
      	yield 2    
      	print('Step 3')    
      	yield 3
      #生成器用next调用
      g = odd()#生成生成器
      one = next(g)
      print(one)
      two = next(g)
      print(two)
      print('*'*20)
      #for 循环调用生成器
      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)

4、协程

  • 3.4引入协程,用yield实现
  • 3.5引入协程语法
  • 实现的协程比较好的包:asyncio,tornado,gevent
  • 定义
    • 是为非抢占式多任务产生子程序的计算机程序组件,协程允许不同入口点在不同位置暂停或开始执行任务
    • 从技术角度将,协程就是一个可以暂停执行的函数
  • 协程的实现
    • yield返回
    • send调用
    def simple():    
    	print('--> start')    
    	x = yield    
    	print('--> recied',x)
    sc = simple()
    print(1111)
    next(sc)#预激
    print(2222)
    sc.send('zhexiao')
  • 协程的四个状态
    • inspect.getgeneratorstate(…) 函数确定,该函数会返回下述字符串中的一个
      • GEN_CREATED:等待执行开始
      • GEN_RUNNING:解释器正在执行
      • GEN_SUSPENED:在yield表达式处暂停
      • GEN_CLOSED:执行结束
    • next:预激
    def simple(a):    
    	print('--> start')    
    	b = yield a    
    	print('--> recied',a,b)    
    	c = yield a+b    
    	print('--> recied',a,b,c)
    sc = simple(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异常,异常对象的vlaue属性会保存返回值
    • yield from从内部捕获StopIteration异常
    def gen():    
    	for c in 'AB':        
    		yield c
    print(list(gen()))
    def gen_new():    
    	yield from "AB"
    print(list(gen_new()))
    • 委派生成器
      • 包含yield from表达式的生成器函数
      • 委派生成器在yield from 表达式暂停,调用方可以直接把数据发给子生成器
      • 子生成器在把产生的值发给调用方
      • 子生成器在最后,解释器会抛出StopIteration,并且把返回值附加到异常对象上 \
      from collections import namedtuple
      '''解释
      1、外层for循环每次迭代会新建一个grouper实例,赋值给coroutine变量:grouper是委派生成
      2、调用next(coroutine),预激委派生成器,此时进入while循环,调用子生成器
      3、内层for循环调用coroutine.send(),直接把值传给子生成器
      4、内层循环结束,grouper实例依旧在yield from表达式处停留
      5、coroutine.send(None)终止average子生成器'''
      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 grouper(storages, key):    
      	while True:        
      		#获取averager的返回值        
      		storages[key] = yield from averager()
      #客户端代码
      def client():    
      	process_data = {'boy2':[39.0,40.8,43.2,40.8,43.1,38.6,41.4,40.6,36.3],'boy1':[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()

5、cayncio

  • python3.4开始引入标准库,内置对异步io的支持
  • asyncio本身是一个消息循环
  • 步骤:
    • 创建消息循环、
    • 导入协程
    • 关闭
    import asyncio         
    #引入异步IO包
    import threading
    #使用协程
    @asyncio.coroutine
    def hello():    
    	print('Hello Word (%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() 
    import asyncio
    @asyncio.coroutine
    def wget(host):    
    	print('wget %s...' % host)    
    	#异步请求网络连接    
    	connect = asyncio.open_connection(host,80)    
    	reader, writer = yield from connect    
    	header = 'GET / HTTP/1.0\r\nHost: %s\r\n\r\n' %host    
    	writer.write(header.encode('uft-8'))    
    	yield from writer.drain()    
    	while True:        
    		line = yield from reader.readline()        
    		#http协议的换行使用b'\r\n'        
    		if line == b'\r\n':            
    			break        
    		print('%s header > %s' %(host, line.decode('utf-8').rstrip()))    
    	writer.close()
    loop = asyncio.get_event_loop()
    tasks = [wget(host) for host in ['www.sina.com.cn', 'www.sohu.com','www.qq.com'
    loop.run_until_complete(asyncio.wait(tasks))
    loop.close()

6、async and await

  • 为了更好地表示IO
  • python3.5引入
  • 让协程代码更简洁
  • 使用上,可以简单的进行替换
    • 用async替换@asyncio.coroutine
    • await替换yield from
    • 和5中的案例一进行比较
    import asyncio         
    #引入异步IO包import threading
    #使用协程
    #@asyncio.coroutine
    async def hello():    
    	print('Hello Word (%s' % threading.currentThread())    
    	print('Start....(%s)' % threading.currentThread())    
    	await 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()

7、aiohttp

  • asyncio实现单线程的并发io,在客户端用处不大
  • 在服务器端可以asyncio+coroutine配合,因为http是Io操作
  • asyncio实现了tcp,udp,ssl等协议
  • pip install aiohttp安装
import asyncio
from aiohttp import web
async def index(request):    
	await asyncio.sleep(0.5)    
	return web.Response(body=b'<h1>Index</h1>')
async def hello(request):    
	await asyncio.sleep(0.5)    
	text = '<h1>hello, %s!</h1>' % request.match_info['name']    
	return web.Response(body=text.encode('utf-8'))
async def init(loop):    
	app = web.Applicat(loop=loop)    
	app.router.add_route('GET','/',index)    
	app.router.add_route('GET','/hello/{name}',hello)    
	srv = await loop.creat_server(app.make_handler(),'124.0.0.1',800)    
	print('Server started at http://127.0.0.1:8000...')
    	return srv
loop = asyncio.get_event_loop()
loop.run_until_complete(init(loop))
loop.run_forever()

8、concurrent.futures

  • python3新增的库
  • 类似于其他语言的线程池的概念
  • 利用multiprocessing实现真正的并行计算
  • 核心原理:
    以子进程的形式,并行运行多个python解释器,从而命令python程序可以利用多核CPU来提升执行速度。由于子进程与主解释器相分离,所以他们的全局解释器锁也是相互独立的,每个子进程都能够完整的使用CPU内核。
  • 使用:
    1、concurrent.futures.Executer
    ThreadPoolExecutor
    ProcessPoolExecuter
    以上执行的时候自行选择
    2、submit(fn,args,kwargs)
    fn:异步执行的函数
    args,kwargs参数
from concurrent.futures import ThreadPoolExecutor
import time 
def return_future(msg):    
	time.sleep(3)    
	return msg
#创建一个线程池
pool = ThreadPoolExecutor(max_workers=2)
#在线程池中加入2个task
f1 = pool.submit(return_future,'hello')
f2 = pool.submit(return_future,'world')
print(f1.done())
time.sleep(3)
print(f2.done())
print(f1.result())
print(f2.result())

9、current中的map函数

  • map(fn,*iterables,timeout=None)
    • 和map函数类似 - 函数需要异步执行
    • timeout:超时时间
    • map 和 submit 使用一个就行
import time, re import os, datetime
from concurrent import futures
data = ['1','2']
def wait_on(argument):    
	print(argument)    
	time.sleep(2)    
	return 'OK'
ex = futures.ThreadPoolExecutor(max_workers=2)
for i in ex.map(wait_on,data):   
	print(i)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值