什么是协程

协程,又称微线程,纤程。英文名Coroutine。一句话说明什么是线程:协程是一种用户态的轻量级线程

协程的特点

协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此:

协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置。

协程的优点

  • 无需线程上下文切换的开销
  • 无需原子操作锁定及同步的开销

    "原子操作(atomic operation)是不需要synchronized",所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个线程)。原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序是不可以被打乱,或者切割掉只执行部分。视作整体是原子性的核心。(因为携程只有一个线程)

  • 方便切换控制流,简化编程模型
  • 高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。(一个进程一个携程,而携程又可以开多个携程,CPU一个核心开一个进程)

协程的缺点

  • 无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。
  • 进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序 (携程类似以一个管道,如果一个地方堵住了,那么整个就不通了)

最底层的协程

使用yield实现协程操作例子

一个服务端在创建,而两个客户端在接收。在单线程上几乎同时执行,代码如下:

  1. #客户的方法
  2. def customer(name):
  3. print("===准备买东西===")
  4. while True:
  5. ret = yield
  6. print("名字:%s,买了:%s"%(name,ret))
  7.  
  8. #服务端
  9. def produce(num):
  10. next(cus1)
  11. next(cus2)
  12. values = 0
  13. while values < num:
  14. values +=1
  15. cus1.send(values)
  16. cus2.send(values)
  17.  
  18. print("谢谢惠顾")
  19.  
  20. if __name__ == "__main__":
  21. cus1 = customer("小明") #创建2个客户端方法的对象
  22. cus2 = customer("小白")
  23.  
  24. produce(5)
  25. #运用生成器的,yield,send,next的特性就可以弄一个最简单的协程

  

Python内部来实现协程的模块gevent

gevent模块不属于Python标准库的模块,要的话得自己下载。下面就让我们看看怎么下载。

我们也可以用greenlet模块实现的协程

greenlet模块也是刚刚在下载gevent模块才有的模块。from greenlet import greenlet ,创建协程对象的方法其实有2个参数“greenlet(run=None,parent = None)”。参数“run”就是要调用的方法,比如下例子中的t1,t2,参数“parent”定义了该协程的父协程,也就是说,greenlet协程直接是可以有父子关系的。如果不设或设为空,则其父协程就是程序默认的“main”主协程。而在要调用的方法,如下面的t1对象中,有一个重要的方法t1.switch(),这个方法的意思就是暂停当前的方法,切换到t1。

实例如下代码

  1. from greenlet import greenlet #调用模块中的方法
  2.  
  3. def fun1():
  4. print('a')
  5. t2.switch()
  6. print('b')
  7.  
  8. def fun2():
  9. print('c')
  10. t1.switch()
  11. print('d')
  12.  
  13. t1 = greenlet(fun1) #创建greenlet对象
  14. t2 = greenlet(fun2)
  15.  
  16. t1.switch() #执行t1
  17.  
  18. #我们可以看到只执行了acb,d并没有执行,因为fun1后面还少了个switch()
  19. #所以可以看出switch还有暂停作用

  

Gevent下所支持的协程

在讲这个之前引进一个内容

猴子补丁 Monkey patching

了实现网络通信的高并发,但是,Gevent直接修改标准库里面大部分的阻塞式系统调用,包括socket、ssl、threading和 select等模块,而变为协作式运行。但是我们无法保证你在复杂的生产环境中有哪些地方使用这些标准库会由于打了补丁而出现奇怪的问题。

一种方法是使用gevent下的socket模块,我们可以通过”from gevent import socket”来导入。不过更常用的方法是使用猴子布丁(Monkey patching)。使用猴子补丁褒贬不一,但是官网上还是建议使用”patch_all()”,而且在程序的第一行就执行。猴子补丁也在Gevent模块的方法中。

Gevent 实现了异步I/O的协程,也就是说只有在遇到I/O阻塞的时候才能切换到其他的方法,而这个I/O阻塞即是可以是执行代码的偶然,也可以是我们定义的必然。

import gevent 这个gevent模块

在看代码之前要知道gevent方法这个对象中的几个方法:

spawn(func,func_args)  func:加入要实现gevent的方法的名字,func_args:方法要传入的参数    创建协程实例

joinall([spawn_list,])    spawn_list:添加入我们刚刚创建的gevent对象              类似于一个同时启动

sleep(time)       time:时间(秒)                           交出CPU控制权限,时间为秒,类似于一个I/O阻塞。这里不能用time.sleep代替

getcurrent()                                         获取当前协程内存地址

下面就让我们来看看例子:

  1. from gevent import monkey #引入monkey方法
  2.  
  3. import gevent,time
  4.  
  5. monkey.patch_all() #这个在小的协程中体现不出效果,不过建议加下。养成个习惯
  6.  
  7. def a():
  8. print("1")
  9. gevent.sleep(2) #模拟I/O阻塞2秒
  10. print("2")
  11.  
  12. def b():
  13. print("3")
  14. gevent.sleep(1)
  15. print("4")
  16.  
  17. start = time.time()
  18. gevent.joinall([ #这里必须是个列表
  19. gevent.spawn(a),
  20. gevent.spawn(b),
  21. ]
  22. )
  23.  
  24. print(time.time()-start)
  25. #这里可以看到实际上才执行了2秒多一点

  

Python 协程 61的更多相关文章

  1. Python 协程总结

    Python 协程总结 理解 协程,又称为微线程,看上去像是子程序,但是它和子程序又不太一样,它在执行的过程中,可以在中断当前的子程序后去执行别的子程序,再返回来执行之前的子程序,但是它的相关信息还是 ...

  2. day-5 python协程与I/O编程深入浅出

    基于python编程语言环境,重新学习了一遍操作系统IO编程基本知识,同时也学习了什么是协程,通过实际编程,了解进程+协程的优势. 一.python协程编程实现 1.  什么是协程(以下内容来自维基百 ...

  3. 终结python协程----从yield到actor模型的实现

    把应用程序的代码分为多个代码块,正常情况代码自上而下顺序执行.如果代码块A运行过程中,能够切换执行代码块B,又能够从代码块B再切换回去继续执行代码块A,这就实现了协程 我们知道线程的调度(线程上下文切 ...

  4. 从yield 到yield from再到python协程

    yield 关键字 def fib(): a, b = 0, 1 while 1: yield b a, b = b, a+b yield 是在:PEP 255 -- Simple Generator ...

  5. 关于python协程中aiorwlock 使用问题

    最近工作中多个项目都开始用asyncio aiohttp aiomysql aioredis ,其实也是更好的用python的协程,但是使用的过程中也是遇到了很多问题,最近遇到的就是 关于aiorwl ...

  6. 用yield实现python协程

    刚刚介绍了pythonyield关键字,趁热打铁,现在来了解一下yield实现协程. 引用官方的说法: 与线程相比,协程更轻量.一个python线程大概占用8M内存,而一个协程只占用1KB不到内存.协 ...

  7. [转载] Python协程从零开始到放弃

    Python协程从零开始到放弃 Web安全 作者:美丽联合安全MLSRC   2017-10-09  3,973   Author: lightless@Meili-inc Date: 2017100 ...

  8. 00.用 yield 实现 Python 协程

    来源:Python与数据分析 链接: https://mp.weixin.qq.com/s/GrU6C-x4K0WBNPYNJBCrMw 什么是协程 引用官方的说法: 协程是一种用户态的轻量级线程,协 ...

  9. python协程详解

    目录 python协程详解 一.什么是协程 二.了解协程的过程 1.yield工作原理 2.预激协程的装饰器 3.终止协程和异常处理 4.让协程返回值 5.yield from的使用 6.yield ...

随机推荐

  1. spring Date格式问题

    起因: 在数据库设计中,日期时间等类型字段一般设置为Datetime格式,所以有时在接口请求实体bean中,对应的接口字段的数据类型可能会被设置为Date类型. 而在java常用场景中的时间格式一般有 ...

  2. 1_translation_1

    It is always difficult to start describing a programming language because little details do not make ...

  3. Win10系统下,本地连接远程桌面(Win2016)图解

    1.Win+R在运行框中输入mstsc,回车 2.在出现的远程登陆窗口中,计算机中输入远程桌面IP 3.点击显示选项按钮,在远程桌面窗口中,点击常规(默认),输入登陆的用户名: XXXXXX 4.点击 ...

  4. liteUploader上传控件的封装使用

    //原来的绑定方式 $('#' + frm_name).liteUploader({ script: url, params: { type: "image", size: siz ...

  5. mysql Table 'user' is marked as crashed and should be repaired

    myisamchk -f x:\xxxxxxxxx\MySQL\data\mysql\*.MYI

  6. Java框架spring 学习笔记(十五):操作MySQL数据库

    新建一个工程,添加对数据库的支持 下载mysql驱动包 mysql-connector-java-5.1.7-bin.jar,快捷键ctrl+alt+shift+s,添加jar包到工程 编写JdbcT ...

  7. Java Web解决跨域请求

    要知道跨域请求就要先了解同源策略,那么什么是同源?什么是不同源?简单来说就是,如果两个资源,包括HTML页面.JavaScript脚本.css样式,对应的协议.域名和端口完全相同,那么这两个资源就是同 ...

  8. nginx多域名、多证书

    环境: 一台nginx服务器 192.168.10.251 两台windowsserver2012 IIS服务器 (192.168.10.252.192.168.10.253) 从阿里云上下载ssl证 ...

  9. bind和on的区别

    bind方法与on方法都是事件绑定,但是两者却又有着一个大区别:事件委托 jquery文档中bind和on函数绑定事件的用法: .bind(events [,eventData], handler) ...

  10. easyui 单元格超出鼠标放上弹出全部

    其他方式:https://www.cnblogs.com/raitorei/p/9878192.html onLoadSuccess : function(data) { //单元格超出部分隐藏并鼠标 ...