【Python】协程
协程,又称微线程,纤程。英文名Coroutine。
协程的概念很早就提出来了,但直到最近几年才在某些语言(如Lua)中得到广泛应用。
子程序,或者称为函数,在所有语言中都是层级调用,比如A调用B,B在执行过程中又调用了C,C执行完毕返回,B执行完毕返回,最后是A执行完毕。
所以子程序调用是通过栈实现的,一个线程就是执行一个子程序。
子程序调用总是一个入口,一次返回,调用顺序是明确的。而协程的调用和子程序不同。
协程看上去也是子程序,但执行过程中,在子程序内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行。
注意,在一个子程序中中断,去执行其他子程序,不是函数调用,有点类似CPU的中断。比如子程序A、B:
def A():
print('')
print('')
print('') def B():
print('x')
print('y')
print('z')
假设由协程执行,在执行A的过程中,可以随时中断,去执行B,B也可能在执行过程中中断再去执行A,结果可能是:
1
2
x
y
3
z
但是在A中是没有调用B的,所以协程的调用比函数调用理解起来要难一些。
看起来A、B的执行有点像多线程,但协程的特点在于是一个线程执行,那和多线程比,协程有何优势?
最大的优势就是协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。
第二大优势就是不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。
因为协程是一个线程执行,那怎么利用多核CPU呢?最简单的方法是多进程+协程,既充分利用多核,又充分发挥协程的高效率,可获得极高的性能。
Python对协程的支持是通过generator实现的。
在generator中,我们不但可以通过for循环来迭代,还可以不断调用next()函数获取由yield语句返回的下一个值。
但是Python的yield不但可以返回一个值,它还可以接收调用者发出的参数。
来看例子:
传统的生产者-消费者模型是一个线程写消息,一个线程取消息,通过锁机制控制队列和等待,但一不小心就可能死锁。
如果改用协程,生产者生产消息后,直接通过yield跳转到消费者开始执行,待消费者执行完毕后,切换回生产者继续生产,效率极高:
def consumer():
r = ''
while True:
n = yield r
if not n:
return
print('[CONSUMER] Consuming %s...' % n)
r = '200 OK' def produce(c):
c.send(None)
n = 0
while n < 5:
n = n + 1
print('[PRODUCER] Producing %s...' % n)
r = c.send(n)
print('[PRODUCER] Consumer return: %s' % r)
c.close() c = consumer()
produce(c)
执行结果:
[PRODUCER] Producing 1...
[CONSUMER] Consuming 1...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 2...
[CONSUMER] Consuming 2...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 3...
[CONSUMER] Consuming 3...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 4...
[CONSUMER] Consuming 4...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 5...
[CONSUMER] Consuming 5...
[PRODUCER] Consumer return: 200 OK
注意到consumer函数是一个generator,把一个consumer传入produce后:
首先调用
c.send(None)启动生成器;然后,一旦生产了东西,通过
c.send(n)切换到consumer执行;consumer通过yield拿到消息,处理,又通过yield把结果传回;produce拿到consumer处理的结果,继续生产下一条消息;produce决定不生产了,通过c.close()关闭consumer,整个过程结束。
整个流程无锁,由一个线程执行,produce和consumer协作完成任务,所以称为“协程”,而非线程的抢占式多任务。
最后套用Donald Knuth的一句话总结协程的特点:“子程序就是协程的一种特例。”
【Python】协程的更多相关文章
- Python 协程总结
Python 协程总结 理解 协程,又称为微线程,看上去像是子程序,但是它和子程序又不太一样,它在执行的过程中,可以在中断当前的子程序后去执行别的子程序,再返回来执行之前的子程序,但是它的相关信息还是 ...
- day-5 python协程与I/O编程深入浅出
基于python编程语言环境,重新学习了一遍操作系统IO编程基本知识,同时也学习了什么是协程,通过实际编程,了解进程+协程的优势. 一.python协程编程实现 1. 什么是协程(以下内容来自维基百 ...
- 终结python协程----从yield到actor模型的实现
把应用程序的代码分为多个代码块,正常情况代码自上而下顺序执行.如果代码块A运行过程中,能够切换执行代码块B,又能够从代码块B再切换回去继续执行代码块A,这就实现了协程 我们知道线程的调度(线程上下文切 ...
- 从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 ...
- 关于python协程中aiorwlock 使用问题
最近工作中多个项目都开始用asyncio aiohttp aiomysql aioredis ,其实也是更好的用python的协程,但是使用的过程中也是遇到了很多问题,最近遇到的就是 关于aiorwl ...
- 用yield实现python协程
刚刚介绍了pythonyield关键字,趁热打铁,现在来了解一下yield实现协程. 引用官方的说法: 与线程相比,协程更轻量.一个python线程大概占用8M内存,而一个协程只占用1KB不到内存.协 ...
- [转载] Python协程从零开始到放弃
Python协程从零开始到放弃 Web安全 作者:美丽联合安全MLSRC 2017-10-09 3,973 Author: lightless@Meili-inc Date: 2017100 ...
- 00.用 yield 实现 Python 协程
来源:Python与数据分析 链接: https://mp.weixin.qq.com/s/GrU6C-x4K0WBNPYNJBCrMw 什么是协程 引用官方的说法: 协程是一种用户态的轻量级线程,协 ...
- python协程详解
目录 python协程详解 一.什么是协程 二.了解协程的过程 1.yield工作原理 2.预激协程的装饰器 3.终止协程和异常处理 4.让协程返回值 5.yield from的使用 6.yield ...
- Python协程与Go协程的区别二
写在前面 世界是复杂的,每一种思想都是为了解决某些现实问题而简化成的模型,想解决就得先面对,面对就需要选择角度,角度决定了模型的质量, 喜欢此UP主汤质看本质的哲学科普,其中简洁又不失细节的介绍了人类 ...
随机推荐
- List转DataTable(反射) ; 将泛型集合类转换成DataTable ; 将集合类转换成DataTable
public class ConvertX { #region 将集合类转换成DataTable /// <summary> /// 将集合类转换成DataTable /// </s ...
- Oracle触发器给表自身的字段重新赋值出现ORA-04091异常
业务描述如下: 在插入一个表的时候,需要根据一个字段的值更新另一个字段的值.当然也可以通过程序就能很简单得实现,只是这个字段只是数据交换用,和系统主业务没关系,不想修改程序,所以才用触发器的方式实现. ...
- miRTarBase 数据库简介
miRTarBase 是一个手 收集的,经过实验验证过miRNA靶基因的数据库,对于每条miRNA靶基因的记录, 都会赋予1个唯一的 miRNA-target interactions (简称MTs) ...
- interproscan 软件对序列进行GO 注释
interproscan 软件实际上将对输入的查询序列和interpro 数据库中的序列去比对,将比对上的序列对应的GO信息作为查询序列的GO注释 在interpro 数据库中,每条蛋白质序列有一个唯 ...
- linux下redis的安装和集群搭建
一.redis概述 1.1.目前redis支持的cluster特性: 1):节点自动发现. 2):slave->master 选举,集群容错. 3):Hot resharding:在线分片. 4 ...
- [转]Apache 监听端口失败,selinux惹的祸
原文在此 CentOS 下启动Httpd 失败,报 (13)Permission denied: make_sock: could not bind to address [::]:8000 因为 小 ...
- 图解HTTP学习笔记——确认访问用户身份的认证
前言 认证功能能让Web页面只被有权限的人访问.而认证机制究竟是怎样一个原理呢?通过今天的学习能对这个有个大致的了解. 正文 什么是认证 计算机无法判断对方的身份,需要客户端自报家门. 服务端为确认客 ...
- saltstack系列1之salt-api配置与使用
salt-api salt-api是我们通过restful-api调用salt-master的接口,且调用的时候必须通过认证才能调用,认证的用户为系统用户,下面就说说如何配置salt-api. 不带S ...
- Python 中遍历序列中元素和下标
enumerate 函数用于遍历序列中的元素以及它们的下标 for i,v in enumerate(['tic','tac','toe']): print i,v #0 tic #1 tac #2 ...
- 【matlab】命令行窗口一直不停的输出ans=1?
ans= 1 matlab里面的ans是一个系统量,当m文件中出现非赋值性的计算时,matlab会把结果自动存入ans. 如果m文件中每一个计算都是赋值的,即所计算的结果都是保存在自己设定的变量中的, ...