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一个状态 ...
随机推荐
- 浅析http缓存
1.什么是缓存 将服务器上的静态资源,保存在本地,当发送web请求的时候,如果本地有“已缓存”的静态资源,则从使用本地保存的静态资源,而不是从源原服务器再次请求. 2.缓存的优点 缓存减少冗余的数据传 ...
- 微信支付接口调用H5(C#)
H5支付是指商户在微信客户端外的移动端网页展示商品或服务,用户在前述页面确认使用微信支付时,商户发起本服务呼起微信客户端进行支付.主要用于触屏版的手机浏览器请求微信支付的场景.可以方便的从外部浏览器唤 ...
- 《JavaScript 高级程序设计》读书笔记三 基本概念
一 语法 区分大小写,驼峰式书写方式: 严格模式:“use strict”: 二 数据类型 a. 基本数据类型: undefined 声明变量未初始化 null 空指针,可以释放内存 Boole ...
- 816. Ambiguous Coordinates
We had some 2-dimensional coordinates, like "(1, 3)" or "(2, 0.5)". Then, we re ...
- 优秀后端架构师必会知识:史上最全MySQL大表优化方案总结
本文原作者“ manong”,原创发表于segmentfault,原文链接:segmentfault.com/a/1190000006158186 1.引言 MySQL作为开源技术的代表作之一,是 ...
- Python学习笔记【第八篇】:Python内置模块
什么时模块 Python中的模块其实就是XXX.py 文件 模块分类 Python内置模块(标准库) 自定义模块 第三方模块 使用方法 import 模块名 form 模块名 import 方法名 说 ...
- Ocelot简易教程(一)之Ocelot是什么
作者:依乐祝 原文地址:https://www.cnblogs.com/yilezhu/p/9557375.html Ocelot简易教程目录 Ocelot简易教程(一)之Ocelot是什么 Ocel ...
- ionic3 生成android 如何控制versionCode版本号
ionic 项目中生成 android 如何控制版本号呢. 1.在项目的配置文件下的config.xml 来我们可以看到 <widget id="com.ionicframework. ...
- ElasticSearch入门1: mac 安装
入门学习顺序: 1. 安装: 1.1 单实例安装: Elastic官方网站: http://www.elastic.co 下载 ElasticSearch: 第一步:点击下载 第二步:点击downlo ...
- C++版 - 剑指offer 面试题5:从尾到头打印链表 题解
面试题5:从尾到头打印链表 提交网址: http://www.nowcoder.com/practice/d0267f7f55b3412ba93bd35cfa8e8035?tpId=13&tq ...