协程greenlet、gevent、猴子补丁

1.协程:微线程(这个概念是在python中有的

进程>线程>协程

一个线程里面可以包含多个协程

协程是通过生成器完成的,yield

协程应用场景:

  有耗时操作的时候应用

耗时操作:网络请求,网络下载(爬虫),IO操作(本地文件的读写),阻塞

 在函数中有yield,函数就变成了生成器,就可以使用next()方法

import time


# 在函数中有yield,函数就变成了生成器,就可以使用next()方法
def task1():
    for i in range(3):
        print('A' + str(i))
        yield
        time.sleep(1)


def task2():
    for i in range(3):
        print('B' + str(i))
        yield
        time.sleep(2)


if __name__ == '__main__':
    g1 = task1()
    g2 = task2()

    while True:
        try:
            next(g1)
            next(g2)
        except:
            break

  

 2.使用greenlet完成协程任务

# 使用greenlet完成协程任务
import time
from greenlet import greenlet


def a():  # 任务A
    for i in range(5):
        print('A' + str(i))
        gb.switch()
        time.sleep(0.1)


def b():  # 任务B
    for i in range(5):
        print('B' + str(i))
        gc.switch()
        time.sleep(0.1)


def c():  # 任务C
    for i in range(5):
        print('C' + str(i))
        ga.switch()
        time.sleep(0.1)


if __name__ == '__main__':
    ga = greenlet(a)
    gb = greenlet(b)
    gc = greenlet(c)

    ga.switch()

  

 3.gevent和猴子补丁(monkey path)

greenlet已经实现了协程,但是这个人工切换,是不是觉得太麻烦了,不要着急,python还有一个比greenlet更强大的并且能够自动切换任务的模块`gevent`
其原理是当一个greentlet遇到IO(指的是input ouput输入输出,比如网络、文件操作等)操作时,比如访问网络,就自动切换到其他的greenlet,等到IO完成,再适当的时候切换回来继续执行。

由于IO操作非常耗时,经常使程序处于等待状态,有了gevent我们自动切换协程,就保证总有greenlet在运行,而不是等待IO

 猴子补丁,将程序中用到的耗时操作的代码,换为gevent中自己实现的模块,如time.sleep(0.1),gevent中也有sleep()方法

一种在运行时候动态修改类,函数的功能的属性编程技巧

1. 在运行时候替换方法,属性

2. 在不修改第三方代码情况下,增加原来不支持对象

3. 运行时为内存中对象增加PATCH,不是在源代码磁盘中增加

import time
import gevent
from gevent import monkey

# 有耗时操作时需要
monkey.patch_all()  # 打补丁,将程序中用到的耗时操作的代码,换为gevent中自己实现的模块


def a():  # 任务A
    for i in range(5):
        print('A' + str(i))
        time.sleep(0.1)


def b():  # 任务B
    for i in range(5):
        print('B' + str(i))
        time.sleep(0.1)


def c():  # 任务C
    for i in range(5):
        print('C' + str(i))
        time.sleep(0.1)


if __name__ == '__main__':
    g1 = gevent.spawn(a)
    g2 = gevent.spawn(b)
    g3 = gevent.spawn(c)

    g1.join()
    g2.join()
    g3.join()

  

4.案例

import requests
import gevent
from gevent import monkey

monkey.patch_all()


def download(url):
    response = requests.get(url)  # 耗时操作
    content = response.text
    print('下载了{}的数据,长度:{}'.format(url, len(content)))


if __name__ == '__main__':
    urls = ['http://www.163.com', 'http://www.qq.com', 'http://www.baidu.com']
    g1 = gevent.spawn(download, urls[0])
    g2 = gevent.spawn(download, urls[1])
    g3 = gevent.spawn(download, urls[2])

    g1.join()
    g2.join()
    g3.join()

    # gevent.joinall(g1, g2, g3)

  

 

posted @ 2020-05-27 16:20  GumpYan  阅读(275)  评论(0编辑  收藏  举报