什么是协程

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

协程的特点

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

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

协程的优点

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

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

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

协程的缺点

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

最底层的协程

使用yield实现协程操作例子

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

#客户的方法
def customer(name):
print("===准备买东西===")
while True:
ret = yield
print("名字:%s,买了:%s"%(name,ret)) #服务端
def produce(num):
next(cus1)
next(cus2)
values = 0
while values < num:
values +=1
cus1.send(values)
cus2.send(values) print("谢谢惠顾") if __name__ == "__main__":
cus1 = customer("小明") #创建2个客户端方法的对象
cus2 = customer("小白") produce(5)
#运用生成器的,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。

实例如下代码

from greenlet import greenlet   #调用模块中的方法

def fun1():
print('a')
t2.switch()
print('b') def fun2():
print('c')
t1.switch()
print('d') t1 = greenlet(fun1) #创建greenlet对象
t2 = greenlet(fun2) t1.switch() #执行t1 #我们可以看到只执行了acb,d并没有执行,因为fun1后面还少了个switch()
#所以可以看出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()                                         获取当前协程内存地址

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

from gevent import monkey   #引入monkey方法

import gevent,time

monkey.patch_all()      #这个在小的协程中体现不出效果,不过建议加下。养成个习惯

def a():
print("1")
gevent.sleep(2) #模拟I/O阻塞2秒
print("2") def b():
print("3")
gevent.sleep(1)
print("4") start = time.time()
gevent.joinall([ #这里必须是个列表
gevent.spawn(a),
gevent.spawn(b),
]
) print(time.time()-start)
#这里可以看到实际上才执行了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. netcore 下加密遇到的问题

    KeyedHashAlgorithm algorithm = KeyedHashAlgorithm.Create(algorithmName.ToString().ToUpper(CultureInf ...

  2. Sping4之依赖注入

    Spring的依赖注入可以是我们不需要去管理bean,网上看到一个回答很精辟: 现在你需要买一把锤子: 1.自己做一把,解释成java就是,调用者创建被调用着,也就是自己去创造一个造锤子的方法,然后自 ...

  3. python,ModuleNotFoundError,is not a package

    Traceback (most recent call last): File "/home/lll/zzz/work/video/zzz/generate.py", line 7 ...

  4. 使用autohotkey修改方向键、回车和启动程序

    具体步骤 下载并安装autohotkey. 在你觉得合适的地方鼠标右键-新建-autohotkey script(脚本):或者创建一个别的文件,再把后缀改成ahk也可以 一个新建的ahk文档里面会有这 ...

  5. Linux - 用户权限相关命令

    用户权限相关命令 目标 用户 和 权限 的基本概念 用户管理 终端命令 组管理 终端命令 修改权限 终端命令 01. 用户 和 权限 的基本概念 1.1 基本概念 用户 是 Linux 系统工作中重要 ...

  6. python之列表及其方法---整理集

    列表类,类名是list 通过list类创建对象,使用中括号 列表特性: 使用中括号括起来 中间用逗号分隔每个元素 元素可以是数字.字符串.布尔值.列表 列表中可以嵌套列表 列表中每个元素的下标从0开始 ...

  7. 记录-springcloud -mybatis

    搭建springcloud与mybatis 从数据库读取数据返回到浏览器 1:我的工程目录 entity  和mapper 中的代码 controller和service的代码 启动类的文件:记得加包 ...

  8. 把Excel作为数据库,读到DataTable中,Excel科学计数法数字转字符串

    需要引用:using System.Data.OleDb; /// <summary> /// 获取Excel数据,包含所有sheet /// </summary> /// & ...

  9. JavaScript 引用错误

    在学习vue时 出现无法实现效果原始设置 <script src="js/lib/vue2.min.js"/><script src="js/lib/v ...

  10. python基础 (初识函数&函数进阶)

    函数基础部分 .什么是函数? 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提高应用的模块性,和代码的重复利用率. 2.定义函数 定义:def 关键词开头,空格之后接函数名 ...