zoukankan      html  css  js  c++  java
  • 协程

    协程

    迭代器

    • 可迭代(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内核
  • 相关阅读:
    Mac014--Sourcetree安装(Git client)
    SSM003/构建Maven单模块项目(二)
    Git016--Work
    Mac013--Docker安装
    前端002/常用标签属性(工作应用)
    Python 38 初识数据库
    Python 38 sql基础
    Python 39 数据库的数据类型
    Python 39 数据库
    Python 37 进程池与线程池 、 协程
  • 原文地址:https://www.cnblogs.com/rener0424/p/10600922.html
Copyright © 2011-2022 走看看