1. 协程:
    #定义来自牛人alex博客
    协程,又称微线程,纤程。英文名Coroutine。一句话说明什么是线程:协程是一种用户态的轻量级线程。
    协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此:
    协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置。
  2.  
  3. 使用协程的目的:就是为了最大限度使用CPU,把IO操作解耦,提高程序运行速度
  4.  
  5. 协程的好处:
    无需线程上下文切换的开销
    无需原子操作锁定及同步的开销
    "原子操作(atomic operation)是不需要synchronized",所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个线程)。原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序是不可以被打乱,或者切割掉只执行部分。视作整体是原子性的核心。
    方便切换控制流,简化编程模型
    高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。
  6.  
  7. 缺点:
    无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。
    进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序
  8.  
  9. greenlet是封装好了的协程
    gevent 是进一步封装了greenlet
  10.  
  11. greenlet还需要通过greenlet.greenlet(func)生成greenlet类实例,只能通过gr1.swich()方法手动切换方法执行。
    gevent通过gevent.spawn(func,args)生成greenlet类实例,通过gevent.joinall([])装载Greenlet实例,即可启动各个方法,并实现自动的遇到IO就切换
    一般在整个当前程序前需要from gevent import monkey引入monkey包,这是个补丁,里边有monkey.patch_all()方法,是明确标记所有IO操作,遇到就切换,
    主要是像socketurllib中的IO操作不会被gevent直接发现时使用这个补丁就能发现了。
    gevent需要自行安装pip install gevent
  1. 必须在只有一个单线程里实现并发
  2. 修改共享数据不需加锁
  3. 用户程序里自己保存多个控制流的上下文栈
  4. 一个协程遇到IO操作自动切换到其它协程
  1.  
  2. 源生的协程
  1. import time
  2. import queue
  3. def consumer(name):
  4. print("--->starting eating baozi...")
  5. while True:
  6. new_baozi = yield
  7. print("[%s] is eating baozi %s" % (name,new_baozi))
  8. #time.sleep(1)
  9.  
  10. def producer():
  11.  
  12. r = con.__next__()
  13. r = con2.__next__()
  14. n = 0
  15. while n < 5:
  16. n +=1
  17. con.send(n)
  18. con2.send(n)
  19. print("\033[32;1m[producer]\033[0m is making baozi %s" %n )
  20.  
  21. if __name__ == '__main__':
  22. con = consumer("c1")
  23. con2 = consumer("c2")
  24. p = producer()

利用模块greenlet写协程,简单一些了

  1. #用greenlet来写个简单的协程,大家猜一下运行结果
  2.  
  3. import greenlet #导入greenlet协程包
  4.  
  5. def green_func1(): #定义第一个协程用的方法
  6. print(12)
  7. gr2.switch() #切换到协程gr2,保存现场,再度切换回来时,从这里开始
  8. print(34)
  9. gr2.switch() #切换到协程gr2,保存现场,再度切换回来时,从这里开始
  10.  
  11. def green_func2(): #定义第二个协程用的方法
  12. print(56)
  13. gr1.switch() #切换回协程gr1,保存现场,再度切换回来时,从这里开始
  14. print(78)
  15.  
  16. gr1=greenlet.greenlet(green_func1) #定义第一个协程,装入方法green_func1方法,并启动协程gr1
  17. gr2=greenlet.greenlet(green_func2) #定义第二个协程,装入方法green_func2方法,并启动协程gr2
  18.  
  19. gr1.switch() #手动切换到协程gr1开始执行。因为没有执行过,所以切换时,从函数开头执行

来个自动的切换吧,这才是真正的写法:

  1. #写个协程抓个网页看看
  2. import gevent,time #引入协程模块
  3. from urllib import request
  4. from gevent import monkey #引入协程模块下的monkey补丁模块
  5. monkey.patch_all() #使用monkey模块下的patch_all()方法,作用是:在每个urllib模块的IO操作前增加标记,来明确协程切换时机
  6.  
  7. def f_get(url): #定义使用协程的方法,
  8. print("GET %s"%url)
  9. resp=request.urlopen(url)
  10. data=resp.read()
  11. print("%d bytes recevied from %s"%(len(data),url))
  12.  
  13. urls=[
  14. "https://www.baidu.com/",
  15. "https://github.com/",
  16. "https://hub.docker.com/",
  17. "https://www.yahoo.com/"
  18. ]
  19.  
  20. print("同步获取:")
  21. ss_time=time.time()
  22. for u in urls:
  23. f_get(u)
  24. print("同步耗时:%s"%(time.time()-ss_time))
  25.  
  26. print("协程异步获取:")
  27. async_time=time.time()
  28. gevent.joinall([ #定义协程的启动,需要传入一个gevent.spawn(其实就是Greenlet类的实例)列表
  29. gevent.spawn(f_get,"https://www.baidu.com/"),
  30. gevent.spawn(f_get,"https://github.com/"),
  31. gevent.spawn(f_get,"https://hub.docker.com/"),
  32. gevent.spawn(f_get,"https://www.yahoo.com/")
  33. ])
  34. print("协程异步耗时:%s"%(time.time()-async_time))
  35.  
  36. print("循环生成Greenlet实例变成列表协程异步获取:")
  37. gl=[]
  38. for uu in urls:
  39. gl.append(gevent.spawn(f_get,uu))
  40. async_time=time.time()
  41. gevent.joinall(gl)#定义协程的启动,需要传入一个gevent.spawn(其实就是Greenlet类的实例)列表
  42. print("协程异步耗时:%s"%(time.time()-async_time))

python3.x Day6 协程的更多相关文章

  1. Python3的原生协程(Async/Await)和Tornado异步非阻塞

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_113 我们知道在程序在执行 IO 密集型任务的时候,程序会因为等待 IO 而阻塞,而协程作为一种用户态的轻量级线程,可以帮我们解决 ...

  2. 运筹帷幄决胜千里,Python3.10原生协程asyncio工业级真实协程异步消费任务调度实践

    我们一直都相信这样一种说法:协程是比多线程更高效的一种并发工作方式,它完全由程序本身所控制,也就是在用户态执行,协程避免了像线程切换那样产生的上下文切换,在性能方面得到了很大的提升.毫无疑问,这是颠扑 ...

  3. 小议Python3的原生协程机制

    此文已由作者张耕源授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 在最近发布的 Python 3.5 版本中,官方正式引入了 async/await关键字.在 asyncio ...

  4. python3 - 多线程和协程速率测试对比

    多线程和协程都属于IO密集型,我通过以下用例测试多线程和协程的实际速率对比. 实例:通过socket客户端以多线程并发模式请求不同服务器端(这里服务器端分2种写法:第一种服务器通过协程实现,第二种服务 ...

  5. Python3 协程相关 - 学习笔记

    什么是协程 协程的优势 Python3中的协程 生成器 yield/send yield + send(利用生成器实现协程) 协程的四个状态 协程终止 @asyncio.coroutine和yield ...

  6. 再议Python协程——从yield到asyncio

    协程,英文名Coroutine.前面介绍Python的多线程,以及用多线程实现并发(参见这篇文章[浅析Python多线程]),今天介绍的协程也是常用的并发手段.本篇主要内容包含:协程的基本概念.协程库 ...

  7. 关于Python的协程问题总结

    协程其实就是可以由程序自主控制的线程 在python里主要由yield 和yield from 控制,可以通过生成者消费者例子来理解协程 利用yield from 向生成器(协程)传送数据# 传统的生 ...

  8. Python3 与 C# 并发编程之~ 协程篇

      3.协程篇¶ 去年微信公众号就陆陆续续发布了,我一直以为博客也汇总同步了,这几天有朋友说一直没找到,遂发现,的确是漏了,所以补上一篇 在线预览:https://github.lesschina.c ...

  9. python3通过gevent.pool限制协程并发数量

    协程虽然是轻量级的线程,但到达一定数量后,仍然会造成服务器崩溃出错.最好的方法通过限制协程并发数量来解决此类问题. server代码: #!/usr/bin/env python # -*- codi ...

随机推荐

  1. python __builtins__ classmethod类 (11)

    11.'classmethod', 修饰符对应的函数不需要实例化,不需要 self 参数,但第一个参数需要是表示自身类的 cls 参数,可以来调用类的属性,类的方法,实例化对象等. class cla ...

  2. bzoj 5210: 最大连通子块和【动态dp+树剖+线段树+堆】

    参考:https://www.cnblogs.com/CQzhangyu/p/8632904.html 要开longlong的 首先看dp,设f[u]为必选u点的子树内最大联通块,p[u]为不一定选u ...

  3. EasyUI设置Layout自适应浏览器宽度和高度

    //设置自适应浏览器宽度和高度 function setLayoutHeight() { var height = $(window).height() - 20; $("#main_lay ...

  4. 1.基础数据类型的初识 字符串 bool 整型 if else elif

    ---恢复内容开始--- 计算器基础知识 cpu :人类的大脑 运算和处理问题 内存:临时存储数据 断点就消失了 高铁 硬盘:永久存储数据 图片 操作系统:是一个软件 控制每个硬件之间的数据交互 Py ...

  5. NSA互联网公开情报收集指南:迷宫中的秘密·下

    猫宁!!! 参考链接: https://www.nsa.gov/news-features/declassified-documents/assets/files/Untangling-the-Web ...

  6. Ubuntu 18.04 LTS 安装后 各种问题以及解决方案

    1. root的初始密码,默认是不知道的,需要进行设置 a. 进入终端自己的用户 b. 输入 sudo passwd回车 c. 输入新密码,回车,重复,回车,搞定 d. su 一下,就可以了 2.  ...

  7. eclipse | 配置JRE

    Window --> Preference --> Java ---> Installed JREs

  8. redis优势

    redis是高性能的key-value内存数据库. 由于是内存型的,所以性能相比磁盘数据库更加优秀. 由于支持丰富的数据类型,相比memcache更受开发者欢迎.列表和整形是最常用的数据类型. 就算对 ...

  9. python实现基数排序

    # 基数排序有着局限性,只能是整数,# 排序的时候要先排后面一个条件的(多条件排序)#如本例中,先从个位开始排起# 多关键字排序# 从低关键字开始排序 # @File: radix_sort #### ...

  10. Queue Sequence HDU - 4441

    码力不行啊... 错误记录: 171行后面对find2的使用错误,原来写的是p=find2(rt,p1),然后再加上一句能过样例但很假的特判 事实上,现在是要寻找最大的j,使得d2[1..j-1]=p ...