python--gevent协程及协程概念

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

何为协程 


 

  协程,又称微线程。英文名Coroutine。

  协程最大的优势就是协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。

  第二大优势就是不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。

  因为协程是一个线程执行,那怎么利用多核CPU呢?最简单的方法是多进程+协程,既充分利用多核,又充分发挥协程的高效率,可获得极高的性能。后续会就这一块单独开写一篇协程+多进程的测试文章。

  Python对协程的支持还非常有限,用在generator中的yield可以一定程度上实现协程。虽然支持不完全,但已经可以发挥相当大的威力了。

 

例子:

  传统的生产者-消费者模型是一个线程写消息,一个线程取消息,通过锁机制控制队列和等待,但一不小心就可能死锁。

  如果改用协程,生产者生产消息后,直接通过yield跳转到消费者开始执行,待消费者执行完毕后,切换回生产者继续生产,效率极高:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

import time

 

def consumer():

    = ''

    while True:

        = yield r

        if not n:

            return

        print('[CONSUMER] Consuming %s...' % n)

        time.sleep(1)

        = '200 OK'

 

def produce(c):

    c.next()

    = 0

    while n < 5:

        = + 1

        print('[PRODUCER] Producing %s...' % n)

        = c.send(n)

        print('[PRODUCER] Consumer return: %s' % r)

    c.close()

 

if __name__=='__main__':

    = consumer()

    produce(c)

  运行结果

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

[PRODUCER] Producing 1...

[CONSUMER] Consuming 1...

[PRODUCER] Consumer return200 OK

[PRODUCER] Producing 2...

[CONSUMER] Consuming 2...

[PRODUCER] Consumer return200 OK

[PRODUCER] Producing 3...

[CONSUMER] Consuming 3...

[PRODUCER] Consumer return200 OK

[PRODUCER] Producing 4...

[CONSUMER] Consuming 4...

[PRODUCER] Consumer return200 OK

[PRODUCER] Producing 5...

[CONSUMER] Consuming 5...

[PRODUCER] Consumer return200 OK

  

注意到consumer函数是一个generator(生成器),把一个consumer传入produce后:

  1. 首先调用c.next()启动生成器;

  2. 然后,一旦生产了东西,通过c.send(n)切换到consumer执行;

  3. consumer通过yield拿到消息,处理,又通过yield把结果传回;

  4. produce拿到consumer处理的结果,继续生产下一条消息;

  5. produce决定不生产了,通过c.close()关闭consumer,整个过程结束。

整个流程无锁,由一个线程执行,produce和consumer协作完成任务,所以称为“协程”,而非线程的抢占式多任务。

 

gevent模块


  

  Python通过yield提供了对协程的基本支持,但是不完全。而第三方的gevent为Python提供了比较完善的协程支持。

  gevent是第三方库,通过greenlet实现协程,其基本思想是:

  当一个greenlet遇到IO操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO。

  由于切换是在IO操作时自动完成,所以gevent需要修改Python自带的一些标准库,这一过程在启动时通过monkey patch完成:

复制代码

import gevent

def f(n):
    for i in range(n):
        print gevent.getcurrent(), i

g1 = gevent.spawn(f, 5)
g2 = gevent.spawn(f, 5)
g3 = gevent.spawn(f, 5)
g1.join()
g2.join()
g3.join()
 

复制代码

 

复制代码

<Greenlet at 0x10e49f550: f(5)> 0
<Greenlet at 0x10e49f550: f(5)> 1
<Greenlet at 0x10e49f550: f(5)> 2
<Greenlet at 0x10e49f550: f(5)> 3
<Greenlet at 0x10e49f550: f(5)> 4
<Greenlet at 0x10e49f910: f(5)> 0
<Greenlet at 0x10e49f910: f(5)> 1
<Greenlet at 0x10e49f910: f(5)> 2
<Greenlet at 0x10e49f910: f(5)> 3
<Greenlet at 0x10e49f910: f(5)> 4
<Greenlet at 0x10e49f4b0: f(5)> 0
<Greenlet at 0x10e49f4b0: f(5)> 1
<Greenlet at 0x10e49f4b0: f(5)> 2
<Greenlet at 0x10e49f4b0: f(5)> 3
<Greenlet at 0x10e49f4b0: f(5)> 4

复制代码

可以看到,3个greenlet是依次运行而不是交替运行。

要让greenlet交替运行,可以通过gevent.sleep()交出控制权:

复制代码

import gevent

def f(n):
    for i in range(n):
        print gevent.getcurrent(), i

g1 = gevent.spawn(f, 5)
g2 = gevent.spawn(f, 5)
g3 = gevent.spawn(f, 5)
g1.join()
g2.join()
g3.join() 

复制代码

复制代码

<Greenlet at 0x10e49f550: f(5)> 0
<Greenlet at 0x10e49f550: f(5)> 1
<Greenlet at 0x10e49f550: f(5)> 2
<Greenlet at 0x10e49f550: f(5)> 3
<Greenlet at 0x10e49f550: f(5)> 4
<Greenlet at 0x10e49f910: f(5)> 0
<Greenlet at 0x10e49f910: f(5)> 1
<Greenlet at 0x10e49f910: f(5)> 2
<Greenlet at 0x10e49f910: f(5)> 3
<Greenlet at 0x10e49f910: f(5)> 4
<Greenlet at 0x10e49f4b0: f(5)> 0
<Greenlet at 0x10e49f4b0: f(5)> 1
<Greenlet at 0x10e49f4b0: f(5)> 2
<Greenlet at 0x10e49f4b0: f(5)> 3
<Greenlet at 0x10e49f4b0: f(5)> 4

复制代码

3个greenlet交替运行,

把循环次数改为500000,让它们的运行时间长一点,然后在操作系统的进程管理器中看,线程数只有1个。

当然,实际代码里,我们不会用gevent.sleep()去切换协程,而是在执行到IO操作时,gevent自动切换,代码如下:

复制代码

from gevent import monkey; monkey.patch_all()#有IO才做时需要这一句
import gevent
import urllib2

def f(url):
    print('GET: %s' % url)
    resp = urllib2.urlopen(url)
    data = resp.read()
    print('%d bytes received from %s.' % (len(data), url))

gevent.joinall([
        gevent.spawn(f, 'https://www.python.org/'),
        gevent.spawn(f, 'https://www.yahoo.com/'),
        gevent.spawn(f, 'https://github.com/'),
]) 

复制代码

复制代码

GET: https://www.python.org/
GET: https://www.yahoo.com/
GET: https://github.com/
45661 bytes received from https://www.python.org/.
14823 bytes received from https://github.com/.
304034 bytes received from https://www.yahoo.com/.

复制代码

从结果看,3个网络操作是并发执行的,而且结束顺序不同,但只有一个线程。

小结

使用gevent,可以获得极高的并发性能,但gevent只能在Unix/Linux下运行,在Windows下不保证正常安装和运行,在windows下需要安装第三方编译好的包,或者自行编译。

 

参考文章: 

  http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001407503089986d175822da68d4d6685fbe849a0e0ca35000

python------- 协程(微线程) 协程 文章目录概念 :优点 :缺点 :特点 :yield的实现greenlet模块gevent模块 概念 : 是单线程下的并发,又称微线程,纤程。英文名Coroutine。 简单的解释:协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的。 优点 : 协程的切换销更小,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级 单线程内就可以实现并发的效果,最大限度地利用CPU、 缺... 阅读详情

相关推荐

详解python协程gevent模块(python协程模型)

在任何一个时刻,操作系统都只能执行一个进程代码,当操作系统决定把控制权从当前进程转移到某个新进程时,就会进行上下文切换,即保存当前进程的上下文,恢复新进程的上下文,然后将控制权传递到新进程,新进程就会从它上次停止的地方始。在下面的例子中,5个waiter协程都会等待事件evt,当setter协程在3秒后设置evt事件,所有的waiter协程即被唤醒。执行流的调度者不同,进程是内核调度,而协程是在用户态调度,也就是说进程的上下文是在内核态保存恢复的,而协程是在用户态保存恢复的,很显然用户态的代价更低。

weixin_46687533的博客 395

Pythongevent

简介 Python 脚本执行的时候不是很快,特别是 Python 下面的多线程机制,长久以来一直被大家所诟病。通常来说要让 Python 执行效率变高一般使用的方法包括: 将复杂的代码转由 C 等执行效率更高的语言完成 多进程并发执行 用多线程完成 IO 操作 使用 gevent 协程机制 本篇博客将简单介绍一下协程协程的基本原理 gevent 的基本原理来自于 libevent...

PythonGo 1127

Python 高性能并发框架 Gevent、后门程序

gevent 是一个基于协程Python 网络库,它使用 greenlet 在 libev 或 libuv 事件循环之上提供高级同步 API。gevent 实现了python 标准库里面大部分的阻塞式系统调用,包括 socket、ssl、threading 和 select 等模块,可以使用 "猴子补丁" 将这些阻塞式调用变为协作式运行。

freeking101的博客 6万+

【小沐学PythonPython实现Web服务器(Flask,gevent

gevent 是一个基于协程Python 网络库,它使用 greenlet 在 libev 或 libuv 事件循环之上提供高级同步 API。╮( ̄▽ ̄)╭如果您感觉方法或代码不咋地//(ㄒoㄒ)//,就在评论处留言,作者继续改进;o_O???如果您需要相关功能的代码定制化发,可以留言私信作者;(✿◡‿◡)!!

爱看书的小沐 6136

python gevent协程模块详解

进程、线程、协程区分 我们通常所说的协程Coroutine其实是corporate routine的缩写,直接翻译为协同的例程,一般我们都简称为协程。 在linux系统中,线程就是轻量级的进程,而我们通常也把协程称为轻量级的线程即微线程。 进程和协程 下面对比一下进程和协程的相同点和不同点: 相同点: 相同点存在于,当我们挂起一个执行流的时,我们要保存的东西: 栈, 其实在你切换前你的局部变量,以及要函数的调用都需要保存,否则都无法恢复 寄存器状态,这个其实用于当你的执行流恢复后要做什么 而寄存器和栈的

爱死亡机器人 1744

探索 Python 异步编程的利器:gevent

gevent库为 Python 发者提供了一种强大的异步编程解决方案,使得编写高效、易于理解的并发代码成为可能。通过本篇文章,我们了解了gevent的基本概念、安装方法、基本函数的使用,以及在实际场景中的应用。同时,我们也探讨了一些常见的问题及其解决方案。希望这些信息能够帮助你更好地利用gevent库,提升你的 Python 异步编程能力。

AIGC搞起 1647

Pythongevent协程协程概念

https://www.cnblogs.com/tkqasn/p/5705338.html 何为协程 协程,又称微线程。英文名Coroutine。 协程最大的优势就是协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的销,和多线程比,线程数量越多,协程的性能优势就越明显。 第二大优势就是不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。 因为协程是一个线程执行,那怎么利用多核CP

u013238956的博客 245

python asyncio与gevent对比_Python协程概念及其用法

本文将先介绍协程概念,然后分别介绍Python2.x与3.x下协程的用法,最终将协程与多线程做比较并介绍异步爬虫模块。协程概念协程,又称微线程,纤程,英文名Coroutine。协程的作用,是在执行函数A时,可以随时中断,去执行函数B,然后中断继续执行函数A(可以自由切换)。但这一过程并不是函数调用(没有调用语句),这一整个过程看似像多线程,然而协程只有一个线程执行。优势·执行效率极高,因为子程...

weixin_39535125的博客 1302

协程概念Python中利用第三方库gevent使用协程

提到程序的并发操作,大多数人程序员首先想到的进程或者线程。我们先复习一下进程和线程的概念。   进程: 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序执行的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实

刘宇(LY)个人笔记 1109

python协程概念gevent使用注意事项及三个案例

协程基本概念 协程本质就是一条线程,它能实现多个任务在一条线程上来回切换执行。 使用协程可以在执行任务遇到IO时切换到别的任务继续执行,避免进入阻塞态,提高了CPU利用率。另外降低了操作系统负担。 进程、线程、协程的区别 进程 线程 协程 操作系统资源分配的最小单位 操作系统调度执行的最小单位 操作系统不可见 内存隔离 内存共享 内存共享 数据不安全 数据不安全 数据安全 销大 销小 销极小 发生IO时都能感知,由操作系统负责切换 发生IO时都能感知,由操作系统负责切换

m0_47670683的博客 1425

Python协程gevent

Python协程gevent1. gevent的介绍2. gevent的使用3. gevent切换执行4. 给程序打补丁5. 注意 1. gevent的介绍 greenlet已经实现了协程,但是这个还要人工切换,这里介绍一个比greenlet更强大而且能够自动切换任务的第三方库,那就是geventgevent内部封装的greenlet,其原理是当一个greenlet遇到IO(指的是input output 输入输出,比如网络、文件操作等)操作时,比如访问网络,就自动切换到其他的greenlet,等到

汪云辉的博客 3617

协程gevent模块的使用

什么是协程?协又叫又称微线程,英文名Coroutine,协程python个中另外一种实现多任务的方式,只不过比线程更小占用更小执行单元(理解为需要的资源)。 为啥说它是一个执行单元,因为它自带CPU上下文。这样只要在合适gr的时机, 我们可以把一个协程 切换到另一个协程。 只要这个过程中保存或恢复 CPU上下文那么程序还是可以运行的。通俗的描述:协程看做是是线程中的一个特殊的函数,这个函数执行的时候,可以在某个地方暂停,并且可以重新在暂停处,继续运行,协程在进行切换的时候,只需要保存当前协程函数中的一些临

henry_rhy的博客 2382

协程基础了解

目录 一.概念 协程是啥 协程和线程差异 二.协程介绍 三.Greenlet模块 四.Gevent模块 一.概念 之前我们学习了线程、进程的概念,了解了在操作系统中进程是资源分配的最小单位,线程是CPU调度的最小单位。按道理来说我们已经算是把cpu的利用率提高很多了。但是我们知道无论是创建多进程还是创建多线程来解决问题,都要消耗一定的时间来创建进程、创建线程、以及管理他们之间的切换。 随着我们对于效率的追求不断提高,基于单线程来实现并发又成为一个新的课题,即只用一个主 线程(.

jcf52的博客 763

Python使用gevent实现协程

Python使用gevent实现协程 Python中多任务的实现可以使用进程和线程,也可以使用协程。 一、协程介绍 协程,又称微线程。英文名Coroutine。协程Python语言中所特有的,在其他语言中没有。 协程python中另外一种实现多任务的方式,比线程更小、占用更小执行单元(理解为需要的资源)。 在一个线程中的某个函数,可以在任何地方保存当前函数的一些临时变量等信息,然后切...

weixin_43790276的博客 2783

Python Gevent协程机制

参考资料 http://www.gevent.org/contents.html https://uwsgi-docs-zh.readthedocs.io/zh_CN/latest/Gevent.html Python脚本的执行效率一直来说并不是很高,特别是Python下的多线程机制,长久以来一直被人们诟病。很多人都在思考如何让Python执行的更快一些,其中典型的方式包括: 将复杂的代码转由C语言完成 多进程并发执行 多线程完成IO操作 然后,人们讨论的更多的则是Gevent协程机制。在理解Gevent

西涛offbye-移动全栈技术博客 1012

Python 协程 gevent 模块

Python 协程 gevent 模块 文章目录Python 协程 gevent 模块

贤哲XianZhe的博客 462

python 协程gevent.pool_python并发编程之gevent协程(四)

协程的含义就不再提,在py2和py3的早期版本中,python协程的主流实现方法是使用gevent模块。由于协程对于操作系统是无感知的,所以其切换需要程序员自己去完成。系列文章基于生成器的简单协程import timedef A():for i in range(100):print("----A---")yield itime.sleep(0.5)def B(c):while True:prin...

weixin_39552317的博客 714
上一篇: python自定义线程池
下一篇: python--multiprocessing多进程总结
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值