• 协程gevent模块的使用


    前言:

    什么是协程?协又叫又称微线程,英文名Coroutine,协程是python个中另外一种实现多任务的方式,只不过比线程更小占用更小执行单元(理解为需要的资源)。 为啥说它是一个执行单元,因为它自带CPU上下文。这样只要在合适gr的时机, 我们可以把一个协程 切换到另一个协程。 只要这个过程中保存或恢复 CPU上下文那么程序还是可以运行的。

    通俗的描述:

    • 协程看做是是线程中的一个特殊的函数,这个函数执行的时候,可以在某个地方暂停,并且可以重新在暂停处,继续运行,协程在进行切换的时候,只需要保存当前协程函数中的一些临时变量等信息,然后切换到另外一个函数中执行,并且切换的次数以及什么时候再切换到原来的函数,都可以由开发者自己决定

    • 协成切换的时候,既不涉及到资源切换,也不涉及到操作系统的调度,而是在在同一个程序中切换不同的函数执行,所以协成占用的资源非常少,切换得时候几乎不耗费什么资源。

    • 协程与进程、线程相比并不是一个维度的概念

    • 协程有分为原生协程和第三方库(gevent模块)实现的协程两种

    一、协程的第三方库:gevent模块:

    官方文档:https://www.gevent.org/api/gevent.html

    1. 什么是gevent

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

    2. 协程正常的情况下:遇到异步耗时(IO操作)才会进行切换

      I: input 输入(文件读取,网络请求数据接收)
      o: output 输出(往文件中写内容,发送网络请求)

    3. gevent模式的具体使用

      第一步:在程序中如果希望遇到IO和耗时就进行切换协程中执行,则需要添加补丁
      打补丁的作用是:将普通的耗时和IO操作—>转换为异步耗时和IO操作

      from gevent import monkey
      # 对所有的IO和耗时操作打补丁
      monkey.patch_all()    
      
      • 1
      • 2
      • 3

      第二步:创建并启动协程:gevent.spawn(任务函数)

      # 1. 创建协程对象
      g1 = gevent.spawn(func1)     # 等待协程g1执行结束
      g2 = gevent.spawn(func2)     # 等待协程g2执行结束
      
      • 1
      • 2
      • 3

      第三步:等待协程执行结束

      1. 第一种: join()方法

        #  2、单个协程对象执行结束
        g1.join()
        g2.join()
        
        • 1
        • 2
        • 3
      2. 第二种: gevent.joinall([a,b])

        #  3、多个协程对象时等待协程执行结束
        gevent.joinall([g1,g2])
        
        • 1
        • 2
    4. 实现没有异步耗时(IO操作)时协程是不会执行的

      # 函数 1
      def func1():
          for i in range(3):
              print("=========== 正在做事情1 ============")
              time.sleep(1)     # time模块的等待并不会执行
      
      # 函数 2
      def func2():
          for i in range(4):
              print("=========== 正在做事情2 ============")
              time.sleep(1)
      
      # 1. 创建协程对象
      g1 = gevent.spawn(func1)     # 等待协程g1执行结束
      g2 = gevent.spawn(func2)     # 等待协程g2执行结束
      
      # #  2、等待协程执行结束
      # g1.join()
      # g2.join()
      
      #  3、多个协程对象时等待协程执行结束
      gevent.joinall([g1,g2])
      
      print("========================== 执行结束 ==========================")
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24

      执行结果:

      1. 在上述代码中,去创建协程对象,等待执行结束后,发现两个任务还是一个一个的去执行,并没有同时去执行,这是因为协程只有遇到IO耗时等待的时候才会去执行,而代码中并没有涉及到IO耗时等待的操作,time模块的等待并不会触发。
        在这里插入图片描述
    5. 实现有异步耗时(IO操作)时协程的执行情况

      1. 第一种方式:通常情况下如果要协程去执行,就需要代码里涉及到IO等耗时操作,gevent模快中也有一个sleep方法:

        # 函数1
        def func1():
            for i in range(3):
                print("=========== 正在做事情1 ============")
                gevent.sleep(1)   # 这是异步耗时等待
        
        # 函数2
        def func2():
            for i in range(4):
                print("=========== 正在做事情2 ============")
                gevent.sleep(1)   # 这是异步耗时等待
        
        # 1. 创建协程对象
        g1 = gevent.spawn(func1)     # 等待协程g1执行结束
        g2 = gevent.spawn(func2)     # 等待协程g2执行结束
        
        #  2、多个协程对象时等待协程执行结束
        gevent.joinall([g1,g2])
        
        print("========================== 执行结束 ==========================")
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20

        执行结果:

        1. 在上述代码中,去创建协程对象,等待执行结束后,发现两个任务是并行去执行是,代码中有涉及到IO耗时等待的操作,gevent.sleep(1), 协程遇到IO耗时等待的时候就会去执行。
          在这里插入图片描述
      2. 第二种方式:通常情况下如果要协程去执行,就需要代码里涉及到IO等耗时操作,也可以通过打补丁的方式去执行:

        from gevent import monkey
        
        # 对所有的IO和耗时操作打补丁
        monkey.patch_all()
        
        # 函数1
        def func1():
            for i in range(3):
                print("=========== 正在做事情1 ============")
                time.sleep(1)   
        
        # 函数2
        def func2():
            for i in range(4):
                print("=========== 正在做事情2 ============")
                time.sleep(1)   
        
        # 1. 创建协程对象
        g1 = gevent.spawn(func1)     # 等待协程g1执行结束
        g2 = gevent.spawn(func2)     # 等待协程g2执行结束
        
        #  2、多个协程对象时等待协程执行结束
        gevent.joinall([g1,g2])
        
        print("========================== 执行结束 ==========================")
        
        • 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

        执行结果:

        1. 在上述代码中,首先去进行了打补丁的操作,在实现等待的方式上,使用了time模块,去创建协程对象,等待执行结束后,发现两个任务是并行去执行是,这是因为monkey在进行补丁操作时,自动将普通的耗时和IO操作—>转换为异步耗时和IO操作去执行,所以看到两个任务是并行去执行是。
          在这里插入图片描述
  • 相关阅读:
    从色情直播到直播电商
    JOSEF电流继电器 DL-33 整定范围0.5-2A 柜内安装板前接线
    玩转 Python 集合,这一篇就够了
    Mysql函数
    【Java UI】HarmonyOs如何集成Hawk
    P5488 差分与前缀和
    Elastic Stack从入门到实践(一)--Elastic Stack入门(3)--Logstash入门与Elastic Stack实战
    STM32CubeMX教程27 SDIO - 读写SD卡
    C/C++整数和与均值 2019年9月电子学会青少年软件编程(C/C++)等级考试一级真题答案解析
    【大模型API调用初尝试二】星火认知大模型 &&百度千帆大模型
  • 原文地址:https://blog.csdn.net/qq_40236497/article/details/125623086