• gevent


    一:gevent模块

    import gevent
    
    def f(n):
        for i in range(n):
            print(gevent.getcurrent(), i)
    
    # 创建一个普通的greenlet对象,并进行切换
    g1 = gevent.spawn(f, 5)
    g2 = gevent.spawn(f, 5)
    g3 = gevent.spawn(f, 5)

    # 协程任务添加到事件循环 g1.join() g2.join() g3.join()
    <Greenlet at 0x27dae18: f(5)> 0 <Greenlet at 0x27dae18: f(5)> 1 <Greenlet at 0x27dae18: f(5)> 2 <Greenlet at 0x27dae18: f(5)> 3 <Greenlet at 0x27dae18: f(5)> 4 <Greenlet at 0x27daae8: f(5)> 0 <Greenlet at 0x27daae8: f(5)> 1 <Greenlet at 0x27daae8: f(5)> 2 <Greenlet at 0x27daae8: f(5)> 3 <Greenlet at 0x27daae8: f(5)> 4 <Greenlet at 0x27dabf8: f(5)> 0 <Greenlet at 0x27dabf8: f(5)> 1 <Greenlet at 0x27dabf8: f(5)> 2 <Greenlet at 0x27dabf8: f(5)> 3 <Greenlet at 0x27dabf8: f(5)> 4

     从打印结果来说,并没有起到一个切换的效果,原因是没有遇到一个阻塞的条件

    那么我们人为的制造阻塞,看看情况会是什么样子? 加上 gevent.sleep(1)

    import gevent
    
    def f(n):
        for i in range(n):
            print(gevent.getcurrent(), i)
            gevent.sleep(1)
    
    # 创建一个普通的Greenlet对象并切换
    g1 = gevent.spawn(f, 5)
    g2 = gevent.spawn(f, 5)
    g3 = gevent.spawn(f, 5)
    
    # 将协程任务添加到事件循环,接收一个任务列表
    g1.join()
    g2.join()
    g3.join()
    
    
    
    <Greenlet at 0x29b9e18: f(5)> 0
    <Greenlet at 0x29b9ae8: f(5)> 0
    <Greenlet at 0x29b9bf8: f(5)> 0
    <Greenlet at 0x29b9e18: f(5)> 1
    <Greenlet at 0x29b9ae8: f(5)> 1
    <Greenlet at 0x29b9bf8: f(5)> 1
    <Greenlet at 0x29b9e18: f(5)> 2
    <Greenlet at 0x29b9ae8: f(5)> 2
    <Greenlet at 0x29b9bf8: f(5)> 2
    <Greenlet at 0x29b9e18: f(5)> 3
    <Greenlet at 0x29b9ae8: f(5)> 3
    <Greenlet at 0x29b9bf8: f(5)> 3
    <Greenlet at 0x29b9e18: f(5)> 4
    <Greenlet at 0x29b9ae8: f(5)> 4
    <Greenlet at 0x29b9bf8: f(5)> 4

    gevent.sleep(1) 人为的制造了阻塞,其实内部还是调用的是 wait()方法

    具体解释,参考https://www.cnblogs.com/lyx210019/p/9427146.html

    sleep()方法必须传入参数,参数就是休眠时间,时间到了就会自动醒来。

    wait()方法可以传入参数也可以不传入参数,传入参数就是在参数结束的时间后开始等待,不传参数就是直接等待。

    内部是调用了这个方法,hub.wait(t)

    但是这种形式的协程,需要人为的去控制阻塞,非常不方便,如果能够自己识别阻塞,自己来处理,就好了!

    补丁monkey

    import gevent
    import random
    import time
    
    def f(n,name):
        for i in range(n):
            print(name, i)
            time.sleep(random.random())
    
    gevent.joinall([
            gevent.spawn(f,5,"意大利"),
            gevent.spawn(f,5,"西班牙")
    ])
    
    
    意大利 0
    意大利 1
    意大利 2
    意大利 3
    意大利 4
    西班牙 0
    西班牙 1
    西班牙 2
    西班牙 3
    西班牙 4

    从结果来看:这种形式的 joinall 可以传入time模块的耗时,更加接近真实场景,但是无法实行切换,依然是串行的执行,那么怎么使用monkey进行自动检测阻塞?

    from gevent import monkey
    monkey.patch_all()
    import gevent
    import random
    import time
    
    def f(n,name):
        for i in range(n):
            print(name, i)
            time.sleep(random.random())
    
    gevent.joinall([
            gevent.spawn(f,5,"意大利"),
            gevent.spawn(f,5,"西班牙")
    ])
    
    
    # 结果1:
    意大利 0
    西班牙 0
    西班牙 1
    意大利 1
    西班牙 2
    意大利 2
    西班牙 3
    西班牙 4
    意大利 3
    意大利 4
    # 结果2 意大利 0 西班牙 0 意大利 1 意大利 2 意大利 3 西班牙 1 意大利 4 西班牙 2 西班牙 3 西班牙 4

    结果是time.sleep(random时间不一样),正常的场景也是,每个请求的阻塞时间不一样,因此也是能够实现切换,而且是自动切换,monkey.patch_all()  就替我们解决了

    # 具体解释廖雪峰的讲解 https://www.liaoxuefeng.com/wiki/897692888725344/966405998508320

    import gevent
    from gevent import monkey
    monkey.patch_all()
    import requests
    
    
    def test(url):
        print(url)
        response = requests.get(url)
        print("从网站返回的内容长度为"+str(len(response.content.decode("utf-8"))),url)
    
    
    def main():
        work_list = [
            gevent.spawn(test,"https://www.baidu.com"),
            gevent.spawn(test, "https://www.sohoo.com"),
            gevent.spawn(test, "https://www.sina.com")
        ]
        gevent.joinall(work_list)
    
    if __name__ == '__main__':
        main()
    
    
    # 结果
    https://www.baidu.com
    https://www.sohoo.com
    https://www.sina.com
    从网站返回的内容长度为505551 https://www.sina.com
    从网站返回的内容长度为2349 https://www.baidu.com
    从网站返回的内容长度为2082 https://www.sohoo.com

    从结果上来看,先打印的https://www.baidu.com,但是请求这个网址的时候,monkey检测到了阻塞,立即进行切换,打印了https://www.sohoo.com,也检测到了阻塞,然后切换到打印https://www.sina.com,但是请求新浪没有阻塞或者阻塞时间特别短,获得了数据,并打印。然后百度阻塞接触,打印百度,最后搜狐阻塞完成,打印搜狐。

    # TODO

  • 相关阅读:
    对树的操作(二叉树)
    数据结构之树
    数据结构
    unix网络编程之listen()详解
    算法基础
    哈希表工作原理
    数据结构之栈
    2014年9月面试汇总
    面试知识必备
    JavaScript之JS的执行环境和作用域
  • 原文地址:https://www.cnblogs.com/meloncodezhang/p/12510869.html
Copyright © 2020-2023  润新知