当前位置 : 主页 > 编程语言 > python >

python gevent协程模块详解

来源:互联网 收集:自由互联 发布时间:2022-06-15
文章目录 ​​1. 进程、线程、协程区分​​ ​​1.1 进程和协程​​ ​​1.2 线程和协程​​ ​​2. 简介​​ ​​2.1 greenlets​​ ​​3. 特点​​ ​​4. 安装​​ ​​5. 示例​​ ​​


文章目录

  • ​​1. 进程、线程、协程区分​​
  • ​​1.1 进程和协程​​
  • ​​1.2 线程和协程​​
  • ​​2. 简介​​
  • ​​2.1 greenlets​​
  • ​​3. 特点​​
  • ​​4. 安装​​
  • ​​5. 示例​​
  • ​​5.1 用greenlet执行一个函数​​
  • ​​5.2 创建协程任务​​
  • ​​5.3 同步和异步执行​​
  • ​​5.4 同步vs异步​​


1. 进程、线程、协程区分

我们通常所说的协程Coroutine其实是corporate routine的缩写,直接翻译为协同的例程,一般我们都简称为协程。

在linux系统中,线程就是轻量级的进程,而我们通常也把协程称为轻量级的线程即微线程。

1.1 进程和协程

下面对比一下进程和协程的相同点和不同点:

相同点:

  • 相同点存在于,当我们挂起一个执行流的时,我们要保存的东西:
  • 栈, 其实在你切换前你的局部变量,以及要函数的调用都需要保存,否则都无法恢复 寄存器状态,这个其实用于当你的执行流恢复后要做什么
  • 而寄存器和栈的结合就可以理解为上下文,上下文切换的理解:
    CPU看上去像是在并发的执行多个进程,这是通过处理器在进程之间切换来实现的,操作系统实现这种交错执行的机制称为上下文切换

    操作系统保持跟踪进程运行所需的所有状态信息。这种状态,就是上下文。
    在任何一个时刻,操作系统都只能执行一个进程代码,当操作系统决定把控制权从当前进程转移到某个新进程时,就会进行上下文切换,即保存当前进程的上下文,恢复新进程的上下文,然后将控制权传递到新进程,新进程就会从它上次停止的地方开始。

    不同点:

  • 执行流的调度者不同,进程是内核调度,而协程是在用户态调度,也就是说进程的上下文是在内核态保存恢复的,而协程是在用户态保存恢复的,很显然用户态的代价更低
  • 进程会被强占,而协程不会,也就是说协程如果不主动让出CPU,那么其他的协程,就没有执行的机会。
  • 对内存的占用不同,实际上协程可以只需要4K的栈就足够了,而进程占用的内存要大的多
  • 从操作系统的角度讲,多协程的程序是单进程,单协程
  • 1.2 线程和协程

    既然我们上面也说了,协程也被称为微线程,下面对比一下协程和线程:

  • 线程之间需要上下文切换成本相对协程来说是比较高的,尤其在开启线程较多时,但协程的切换成本非常低。
  • 同样的线程的切换更多的是靠操作系统来控制,而协程的执行由我们自己控制。
  • 协程只是在单一的线程里不同的协程之间切换,其实和线程很像,线程是在一个进程下,不同的线程之间做切换,这也可能是协程称为微线程的原因吧。

    2. 简介

    Gevent模块是一种基于协程的Python网络库,它用到Greenlet提供的,封装了libevent事件循环的高层同步API。它让开发者在不改变编程习惯的同时,用同步的方式写异步I/O的代码。

    2.1 greenlets

    如果想了解gevent的调度流程,最重要的是对greenlet有基本的了解。下面总结一些个人认为比较重要的点:

  • 每一个greenlet.greenlet实例都有一个parent(可指定,默认为创生新的greenlet.greenlet所在环境),当greenlet.greenlet实例执行完逻辑正常结束、或者抛出异常结束时,执行逻辑切回到其parent
  • 可以继承greenlet.greenlet,子类需要实现run方法,当调用greenlet.switch方法时会调用到这个run方法
  • 在gevent中,有两个类继承了greenlet.greenlet,分别是gevent.hub.Hub和gevent.greenlet.Greenlet。后文中,如果是greenlet.greenlet这种写法,那么指的是原生的类库greentlet,如果是greenlet(或者Greenlet)那么指gevent封装后的greenlet。

    gevent中的主要模式, 它是以C扩展模块形式接入Python的轻量级协程。 全部运行在主程序操作系统进程的内部,但它们被程序员协作式地调度。

    在任何时刻,只有一个协程在运行。

    区别于multiprocessing、threading等提供真正并行构造的库, 这些库轮转使用操作系统调度的进程和线程,是真正的并行。

    3. 特点

    基于libev的快速事件循环(Linux上epoll,FreeBSD上kqueue)。
    基于greenlet的轻量级执行单元。
    API的概念和Python标准库一致(如事件,队列)
    可以配合socket,ssl模块使用。
    能够使用标准库和第三方模块创建标准的阻塞套接字(gevent.monkey)
    默认通过线程池进行DNS查询,也可通过c-are(通过GEVENT_RESOLVER=ares环境变量开启)。
    TCP/UDP/HTTP服务器
    子进程支持(通过gevent.subprocess)
    线程池

    4. 安装

    安装和依赖
    依赖于greenlet library
    支持python 2.6+ 、3.3+

    pip install gevent

    5. 示例

    5.1 用greenlet执行一个函数

    #coding:utf-8
    import time
    from greenlet import greenlet

    def eat():
    print('魔降风云变 is eating')
    time.sleep(0.5)
    print('魔降风云变 finished eat')

    def sleep():
    print('小马过河 is sleeping')
    time.sleep(0.5)
    print('小马过河 finished sleep')
    g1 = greenlet(eat)
    g1.switch()

    --------------结果:

    魔降风云变 is eating
    魔降风云变 finished eat

    在一个任务函数中切换到另一个任务函数去执行,然后没有再切换回来

    #coding:utf-8
    import time
    from greenlet import greenlet
    def eat():
    print('魔降风云变 is eating')
    g2.switch()
    time.sleep(0.5)
    print('魔降风云变 finished eat')

    def sleep():
    print('小马过河 is sleeping')
    time.sleep(0.5)
    print('小马过河 finished sleep')
    g1 = greenlet(eat)
    g2 = greenlet(sleep)
    g1.switch()

    --------------结果:

    魔降风云变 is eating
    小马过河 is sleeping
    小马过河 finished sleep

    一个任务中切换到另一个任务,另一个任务执行完了再执行切换回到这个任务执行。实现两个任务间切换并都执行结束

    #coding:utf-8
    import time
    from greenlet import greenlet
    def eat():
    print('魔降风云变 is eating')
    g2.switch()
    time.sleep(0.5)
    print('魔降风云变 finished eat')

    def sleep():
    print('小马过河 is sleeping')
    time.sleep(0.5)
    print('小马过河 finished sleep')
    g1.switch()
    g1 = greenlet(eat)
    g2 = greenlet(sleep)
    g1.switch()

    ------------结果:

    魔降风云变 is eating
    小马过河 is sleeping
    小马过河 finished sleep
    魔降风云变 finished eat

    5.2 创建协程任务

    ``python
    #coding:utf-8
    import time
    import gevent
    def eat():
    print('魔降风云变 is eating')
    time.sleep(1)
    print('魔降风云变 finished eat')
    def sleep():
    print('小马过河 is sleeping')
    time.sleep(1)
    print('小马过河 finished sleep')
    g1 = gevent.spawn(eat) # 创造一个协程任务

    -----------结果:没有输出
    协程遇到阻塞才切换,这里代码从上到下执行结束,没有遇到阻塞

    import time
    import gevent
    def eat():
    print('魔降风云变 is eating')
    time.sleep(1)
    print('魔降风云变 finished eat')
    def sleep():
    print('小马过河 is sleeping')
    time.sleep(1)
    print('小马过河 finished sleep')
    g1 = gevent.spawn(eat) # 创造一个协程任务
    gevent.sleep(2) #加个gevent.sleep(2)就切换到eat执行里面的代码了

    ---------结果:

    魔降风云变 is eating
    魔降风云变 finished eat

    #加个gevent.sleep(2)就切换到eat执行里面的代码了。eat中间time.sleep(1)照样睡。

    5.3 同步和异步执行

    两个子任务之间的 切换也就是上下文切换。
    创建Greenlets,gevent对Greenlet初始化提供了一些封装.
    第一个

    import gevent
    def test1():
    print 12
    gevent.sleep(0)
    print 34
    def test2():
    print 56
    gevent.sleep(0)
    print 78
    gevent.joinall([
    gevent.spawn(test1),
    gevent.spawn(test2),
    ])$ python gevent2.py
    12
    56
    34
    78

    第二个

    import gevent
    from gevent import Greenlet
    def foo(message, n):
    gevent.sleep(n)
    print(message)
    thread1 = Greenlet.spawn(foo, "Hello", 1)
    thread2 = gevent.spawn(foo, "I live!", 2)
    thread3 = gevent.spawn(lambda x: (x+1), 2)
    threads = [thread1, thread2, thread3]
    gevent.joinall(threads)

    第二个

    $ python gevent3.py
    Hello
    I live!

    5.4 同步vs异步

    import gevent
    import random
    def task(pid):
    gevent.sleep(random.randint(0,2)*0.001)
    print('Task %s done' % pid)
    def synchronous():
    for i in xrange(5):
    task(i)
    def asynchronous():
    threads = [gevent.spawn(task, i) for i in xrange(5)]
    gevent.joinall(threads)
    print('Synchronous:')
    synchronous()
    print('Asynchronous:')
    asynchronous()$ python gevent3.py
    Synchronous:
    Task 0 done
    Task 1 done
    Task 2 done
    Task 3 done
    Task 4 done
    Asynchronous:
    Task 2 done
    Task 0 done
    Task 1 done
    Task 3 done
    Task 4 done

    参考连接:

    ​​https://softlns.github.io/2015/11/28/python-gevent/​​

    ​​http://codingdict.com/blog/article/2019/7/11/3560.html​​

    上一篇:python open函数文本操作详解
    下一篇:没有了
    网友评论