python中的协程
协程,又称微线程,纤程。英文名Coroutine。
协程是啥
协程是python个中另外一种实现多任务的方式,只不过比线程更小占用更小执行单元(理解为需要的资源)。 为啥说它是一个执行单元,因为它自带CPU上下文。这样只要在合适的时机, 我们可以把一个协程 切换到另一个协程。 只要这个过程中保存或恢复 CPU上下文那么程序还是可以运行的。
通俗的理解:在一个线程中的某个函数,可以在任何地方保存当前函数的一些临时变量等信息,然后切换到另外一个函数中执行,注意不是通过调用函数的方式做到的,并且切换的次数以及什么时候再切换到原来的函数都由开发者自己确定。
协程和线程差异
在实现多任务时, 线程切换从系统层面远不止保存和恢复 CPU上下文这么简单。 操作系统为了程序运行的高效性每个线程都有自己缓存Cache等等数据,操作系统还会帮你做这些数据的恢复操作。 所以线程的切换非常耗性能。但是协程的切换只是单纯的操作CPU的上下文,所以一秒钟切换个上百万次系统都抗的住。
简单实现协程
import time
def test1():
while True:
print("--test1--")
yield
time.sleep(0.5)
def test2():
while True:
print("--test2--")
yield
time.sleep(0.5)
if __name__ == "__main__":
t1 = test1()
t2 = test2()
while True:
next(t1)
next(t2)
greenlet
安装方式
sudo pip3 install greenlet
import time
from greenlet import greenlet
def test1():
while True:
print("--test1--")
g2.switch()
time.sleep(0.5)
def test2():
while True:
print("--test2--")
g1.switch()
time.sleep(0.5)
g1 = greenlet(test1)
g2 = greenlet(test2)
g1.switch()
运行效果:
--test1--
--test2--
--test1--
--test2--
--test1--
--test2--
--test1--
--test2--
--test1--
。。。
gevent
greenlet已经实现了协程,但是这个还的人工切换,是不是觉得太麻烦了,不要捉急,python还有一个比greenlet更强大的并且能够自动切换任务的模块gevent
其原理是当一个greenlet遇到IO(指的是input output 输入输出,比如网络、文件操作等)操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。
由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO。
安装
pip3 install gevent
1. gevent的使用
import gevent
def test(n):
for i in range(n):
print(gevent.getcurrent(), i)
g1 = gevent.spawn(test, 5)
g2 = gevent.spawn(test, 5)
g3 = gevent.spawn(test, 5)
g1.join()
g2.join()
g3.join()
2. gevent切换执行
import gevent
def test(n):
for i in range(n):
print(gevent.getcurrent(), i)
gevent.sleep(0.5)
g1 = gevent.spawn(test, 5)
g2 = gevent.spawn(test, 5)
g3 = gevent.spawn(test, 5)
g1.join()
g2.join()
g3.join()
运行结果:
<Greenlet "Greenlet-0" at 0x7f04bfffb748: test(5)> 0
<Greenlet "Greenlet-1" at 0x7f04bfffb948: test(5)> 0
<Greenlet "Greenlet-2" at 0x7f04bfffba48: test(5)> 0
<Greenlet "Greenlet-0" at 0x7f04bfffb748: test(5)> 1
<Greenlet "Greenlet-1" at 0x7f04bfffb948: test(5)> 1
<Greenlet "Greenlet-2" at 0x7f04bfffba48: test(5)> 1
<Greenlet "Greenlet-0" at 0x7f04bfffb748: test(5)> 2
<Greenlet "Greenlet-1" at 0x7f04bfffb948: test(5)> 2
<Greenlet "Greenlet-2" at 0x7f04bfffba48: test(5)> 2
<Greenlet "Greenlet-0" at 0x7f04bfffb748: test(5)> 3
<Greenlet "Greenlet-1" at 0x7f04bfffb948: test(5)> 3
<Greenlet "Greenlet-2" at 0x7f04bfffba48: test(5)> 3
<Greenlet "Greenlet-0" at 0x7f04bfffb748: test(5)> 4
<Greenlet "Greenlet-1" at 0x7f04bfffb948: test(5)> 4
<Greenlet "Greenlet-2" at 0x7f04bfffba48: test(5)> 4
3. 给程序打补丁
import time
import gevent
def test(n):
for i in range(n):
print(gevent.getcurrent(), i)
time.sleep(0.5)
g1 = gevent.spawn(test, 5)
g2 = gevent.spawn(test, 5)
g3 = gevent.spawn(test, 5)
g1.join()
g2.join()
g3.join()
运行结果:
<Greenlet "Greenlet-0" at 0x7f1a8dde6748: test(5)> 0
<Greenlet "Greenlet-0" at 0x7f1a8dde6748: test(5)> 1
<Greenlet "Greenlet-0" at 0x7f1a8dde6748: test(5)> 2
<Greenlet "Greenlet-0" at 0x7f1a8dde6748: test(5)> 3
<Greenlet "Greenlet-0" at 0x7f1a8dde6748: test(5)> 4
<Greenlet "Greenlet-1" at 0x7f1a8dde6948: test(5)> 0
<Greenlet "Greenlet-1" at 0x7f1a8dde6948: test(5)> 1
<Greenlet "Greenlet-1" at 0x7f1a8dde6948: test(5)> 2
<Greenlet "Greenlet-1" at 0x7f1a8dde6948: test(5)> 3
<Greenlet "Greenlet-1" at 0x7f1a8dde6948: test(5)> 4
<Greenlet "Greenlet-2" at 0x7f1a8dde6a48: test(5)> 0
<Greenlet "Greenlet-2" at 0x7f1a8dde6a48: test(5)> 1
<Greenlet "Greenlet-2" at 0x7f1a8dde6a48: test(5)> 2
<Greenlet "Greenlet-2" at 0x7f1a8dde6a48: test(5)> 3
<Greenlet "Greenlet-2" at 0x7f1a8dde6a48: test(5)> 4
import time
import gevent
from gevent import monkey
monkey.patch_all() # 讲程序中用到的耗时的代码,换为gevent中实现的代码
def test(n):
for i in range(n):
print(gevent.getcurrent(), i)
time.sleep(0.5)
# g1 = gevent.spawn(test, 5)
# g2 = gevent.spawn(test, 5)
# g3 = gevent.spawn(test, 5)
# g1.join()
# g2.join()
# g3.join()
gevent.joinall([
gevent.spawn(test, 5),
gevent.spawn(test, 5),
gevent.spawn(test, 5)
])
运行结果:
<Greenlet "Greenlet-0" at 0x7f7f96b53648: test(5)> 0
<Greenlet "Greenlet-1" at 0x7f7f96b53748: test(5)> 0
<Greenlet "Greenlet-2" at 0x7f7f96b53848: test(5)> 0
<Greenlet "Greenlet-0" at 0x7f7f96b53648: test(5)> 1
<Greenlet "Greenlet-1" at 0x7f7f96b53748: test(5)> 1
<Greenlet "Greenlet-2" at 0x7f7f96b53848: test(5)> 1
<Greenlet "Greenlet-0" at 0x7f7f96b53648: test(5)> 2
<Greenlet "Greenlet-1" at 0x7f7f96b53748: test(5)> 2
<Greenlet "Greenlet-2" at 0x7f7f96b53848: test(5)> 2
<Greenlet "Greenlet-0" at 0x7f7f96b53648: test(5)> 3
<Greenlet "Greenlet-1" at 0x7f7f96b53748: test(5)> 3
<Greenlet "Greenlet-2" at 0x7f7f96b53848: test(5)> 3
<Greenlet "Greenlet-0" at 0x7f7f96b53648: test(5)> 4
<Greenlet "Greenlet-1" at 0x7f7f96b53748: test(5)> 4
<Greenlet "Greenlet-2" at 0x7f7f96b53848: test(5)> 4
进程、线程、协程对比
请仔细理解如下的通俗描述
- 有一个老板想要开个工厂进行生产某件商品(例如剪子)
- 他需要花一些财力物力制作一条生产线,这个生产线上有很多的器件以及材料这些所有的 为了能够生产剪子而准备的资源称之为:进程
- 只有生产线是不能够进行生产的,所以老板的找个工人来进行生产,这个工人能够利用这些材料最终一步步的将剪子做出来,这个来做事情的工人称之为:线程
- 这个老板为了提高生产率,想到3种办法:
- 在这条生产线上多招些工人,一起来做剪子,这样效率是成倍増长,即单进程 多线程方式
- 老板发现这条生产线上的工人不是越多越好,因为一条生产线的资源以及材料毕竟有限,所以老板又花了些财力物力购置了另外一条生产线,然后再招些工人这样效率又再一步提高了,即多进程 多线程方式
- 老板发现,现在已经有了很多条生产线,并且每条生产线上已经有很多工人了(即程序是多进程的,每个进程中又有多个线程),为了再次提高效率,老板想了个损招,规定:如果某个员工在上班时临时没事或者再等待某些条件(比如等待另一个工人生产完谋道工序 之后他才能再次工作) ,那么这个员工就利用这个时间去做其它的事情,那么也就是说:如果一个线程等待某些条件,可以充分利用这个时间去做其它事情,其实这就是:协程方式
简单总结
- 进程是资源分配的单位
- 线程是操作系统调度的单位
- 进程切换需要的资源很最大,效率很低
- 线程切换需要的资源一般,效率一般(当然了在不考虑GIL的情况下)
- 协程切换任务资源很小,效率高
- 多进程、多线程根据cpu核数不一样可能是并行的,但是协程是在一个线程中 所以是并发
python中的协程的更多相关文章
- python中的协程及实现
1.协程的概念: 协程是一种用户态的轻量级线程.协程拥有自己的寄存器上下文和栈. 协程调度切换时,将寄存器上下文和栈保存到其他地方,在切换回来的时候,恢复先前保存的寄存器上下文和栈. 因此,协程能保留 ...
- python中的协程:greenlet和gevent
python中的协程:greenlet和gevent 协程是一中多任务实现方式,它不需要多个进程或线程就可以实现多任务. 1.通过yield实现协程: 代码: import time def A(): ...
- Python中异步协程的使用方法介绍
1. 前言 在执行一些 IO 密集型任务的时候,程序常常会因为等待 IO 而阻塞.比如在网络爬虫中,如果我们使用 requests 库来进行请求的话,如果网站响应速度过慢,程序一直在等待网站响应,最后 ...
- Python中Paramiko协程方式详解
什么是协程 协程我们可以看做是一种用户空间的线程. 操作系统对齐存在一无所知,需要用户自己去调度. 比如说进程,线程操作系统都是知道它们存在的.协程的话是用户空间的线程,操作系统是不知道的. 为什么要 ...
- 协程及Python中的协程
1 协程 1.1协程的概念 协程,又称微线程,纤程.英文名Coroutine.一句话说明什么是线程:协程是一种用户态的轻量级线程.(其实并没有说明白~) 我觉得单说协程,比较抽象,如果对线程有一定了解 ...
- python中多进程+协程的使用以及为什么要用它
前面讲了为什么python里推荐用多进程而不是多线程,但是多进程也有其自己的限制:相比线程更加笨重.切换耗时更长,并且在python的多进程下,进程数量不推荐超过CPU核心数(一个进程只有一个GIL, ...
- Python | 详解Python中的协程,为什么说它的底层是生成器?
今天是Python专题的第26篇文章,我们来聊聊Python当中的协程. 我们曾经在golang关于goroutine的文章当中简单介绍过协程的概念,我们再来简单review一下.协程又称为是微线程, ...
- Python中的协程,为什么说它的底层是生成器?
我们曾经在golang关于goroutine的文章当中简单介绍过 协程 的概念,我们再来简单review一下.协程又称为是微线程,英文名是Coroutine.它和线程一样可以调度,但是不同的是线程的启 ...
- python中的协程并发
python asyncio 网络模型有很多中,为了实现高并发也有很多方案,多线程,多进程.无论多线程和多进程,IO的调度更多取决于系统,而协程的方式,调度来自用户,用户可以在函数中yield一个状态 ...
随机推荐
- day23_雷神_git
git 版本控制工具 下载: https://git-scm.com/ git clone: 是用来拉代码的,git pull是更新当前分支的代码,拿到最新的代码,git pull是获取已经存在的仓库 ...
- socket实现FTP上传下载功能
'''服务器端''' 1 _author__ = "Dbass" import socketserver import json,os class MyTCPHandler(soc ...
- Jenkins可用环境变量列表以及环境变量的使用(Shell/Command/Maven/Ant)
一.可用环境变量列表(以下来自google翻译): BRANCH_NAME 对于多分支项目,这将被设置为正在构建的分支的名称,例如,如果您希望从而master不是从特征分支部署到生产. CHANGE_ ...
- python 操作 MD5
MD5是什么! Message Digest Algorithm MD5(中文名为消息摘要算法第五版)为计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护.该算法的文件号为RFC 1321 ...
- 了解iOS消息推送一文就够:史上最全iOS Push技术详解
本文作者:陈裕发, 腾讯系统测试工程师,由腾讯WeTest整理发表. 1.引言 开发iOS系统中的Push推送,通常有以下3种情况: 1)在线Push:比如QQ.微信等IM界面处于前台时,聊天消息和指 ...
- 吴恩达机器学习笔记35-诊断偏差和方差(Diagnosing Bias vs. Variance)
当你运行一个学习算法时,如果这个算法的表现不理想,那么多半是出现两种情况:要么是偏差比较大,要么是方差比较大.换句话说,出现的情况要么是欠拟合,要么是过拟合问题.那么这两种情况,哪个和偏差有关,哪个和 ...
- linux创建用户并设置密码
1.在root权限下,useradd只是创建了一个用户名,如(useradd+用户名),它并没有在/home目录下创建同名文件夹,也没有创建密码,因此利用这个用户登录系统,是登录不了的,为了避免这样的 ...
- spring cloud config配置记录
1. spring cloud config配置记录 1.1. pom <!-- 分布式配置中心 --> <dependency> <groupId>org.spr ...
- 浅谈static关键字的四种用法
1.修饰成员变量 在一个person类中,一个成员变量例如 String name,当new2个person()对象时候,这2个对象在堆的位置是不同的,给name赋值张三.李四,这两个对象的name是 ...
- Ajax,JSONP以及跨域问题
没用过裸的Ajax 也没听过jsonp,也不了解跨域问题,emmm… 参考: http://www.runoob.com/ajax/ajax-tutorial.html https://www.lia ...