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一个状态 ...
随机推荐
- 201671010147 2017年8月27号 初学java的感想
在IT行业中,java无疑是最热门的,很多企业也青睐java,因为他的扩展性好,可以处理更多客户的数据,正是因为java有前景所以才吸引更多人去学习.在大一我们已经接触vhleC语言,大二开始就解除了 ...
- MySQL--BNL/ICP/MRR/BKA
#======================================================##MySQL关联查询算法:BNL(Block Nested-Loop)ICP(Index ...
- 前端开发JS白板编程题目若干
在前端开发参加面试的时候,无论是校招还是社招,往往都会碰到让我们直接在白纸或者白板上手撸代码的题目.由于是手撸代码,这些题目肯定不会过于复杂和冗长,否则面试那么一小会时间根本写不完.本文总结了几个我本 ...
- Canal学习笔记(客户端)
前言 最近公司用到Canal来做从MySQL到Tidb的数据同步,用到HA模式Canal,记录一下HA模式的工作原理. Canal的架构模式 Canal是利用binlog日志来做数据同步,canal伪 ...
- 细说SpringDI Setter注入
依赖注入(DI)是一个过程,通过这个过程,对象可以通过构造函数参数,工厂方法的参数或者在构造或返回对象实例后设置的属性来定义它们的依赖关系从工厂方法.然后容器在创建bean时注入这些依赖关系.这个过程 ...
- Python爬虫2-检测编码(使用chardet)
GitHub代码练习地址:https://github.com/Neo-ML/PythonPractice/blob/master/SpiderPrac02_chardet.py 网页编码问题解决 c ...
- Python学习笔记【第二篇】:运算符、比较、关系运算符
运算符 python支持以下几种运算符 算术运算符 运算符 描述 实例 + 加 两个对象相加 a + b 输出结果 30 - 减 得到负数或是一个数减去另一个数 a - b 输出结果 -10 * 乘 ...
- 《http权威指南》读书笔记6
概述 最近对http很感兴趣,于是开始看<http权威指南>.别人都说这本书有点老了,而且内容太多.我个人觉得这本书写的太好了,非常长知识,让你知道关于http的很多概念,不仅告诉你怎么做 ...
- Metasploit Framework(7)客户端渗透(下)
文章的格式也许不是很好看,也没有什么合理的顺序 完全是想到什么写一些什么,但各个方面都涵盖到了 能耐下心看的朋友欢迎一起学习,大牛和杠精们请绕道 应用场景: Kali机器IP:192.168.163. ...
- Kubernetes集群搭建之系统初始化配置篇
Kubernetes的几种部署方式 1. minikube Minikube是一个工具,可以在本地快速运行一个单点的Kubernetes,尝试Kubernetes或日常开发的用户使用.不能用于生产环境 ...