• 协程


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

    协程是啥

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

    通俗的理解:在一个线程中的某个函数,可以在任何地方保存当前函数的一些临时变量等信息,然后切换到另外一个函数中执行,注意不是通过调用函数的方式做到的,并且切换的次数以及什么时候再切换到原来的函数都由开发者自己确定

    协程和线程差异

    在实现多任务时, 线程切换从系统层面远不止保存和恢复 CPU上下文这么简单。 操作系统为了程序运行的高效性每个线程都有自己缓存Cache等等数据,操作系统还会帮你做这些数据的恢复操作。 所以线程的切换非常耗性能。但是协程的切换只是单纯的操作CPU的上下文,所以一秒钟切换个上百万次系统都抗的住。

    简单实现协程

    import time
    
    def work1():
        while True:
            print("----work1---")
            yield
            time.sleep(0.5)
    
    def work2():
        while True:
            print("----work2---")
            yield
            time.sleep(0.5)
    
    def main():
        w1 = work1()
        w2 = work2()
        while True:
            next(w1)
            next(w2)
    
    if __name__ == "__main__":
        main()

    运行结果:

    ----work1---
    ----work2---
    ----work1---
    ----work2---
    ----work1---
    ----work2---
    ----work1---
    ----work2---
    ----work1---
    ----work2---
    ----work1---
    ----work2---
    ...省略...

    greenlet

    为了更好使用协程来完成多任务,python中的greenlet模块对其封装,从而使得切换任务变的更加简单

    安装方式

    使用如下命令安装greenlet模块:

    sudo pip3 install greenlet
    #coding=utf-8
    
    from greenlet import greenlet
    import time
    
    def test1():
        while True:
            print "---A--"
            gr2.switch()
            time.sleep(0.5)
    
    def test2():
        while True:
            print "---B--"
            gr1.switch()
            time.sleep(0.5)
    
    gr1 = greenlet(test1)
    gr2 = greenlet(test2)
    
    #切换到gr1中运行
    gr1.switch()

    运行效果

    ---A--
    ---B--
    ---A--
    ---B--
    ---A--
    ---B--
    ---A--
    ---B--
    ...省略...

    gevent

    greenlet已经实现了协程,但是这个还的人工切换,是不是觉得太麻烦了,不要捉急,python还有一个比greenlet更强大的并且能够自动切换任务的模块gevent

    其原理是当一个greenlet遇到IO(指的是input output 输入输出,比如网络、文件操作等)操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。

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

    pip3 install gevent

    1. gevent的使用

    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是依次运行而不是交替运行

    2. gevent切换执行

    import gevent
    
    def f(n):
        for i in range(n):
            print(gevent.getcurrent(), i)
            #用来模拟一个耗时操作,注意不是time模块中的sleep
            gevent.sleep(1)
    
    g1 = gevent.spawn(f, 5)
    g2 = gevent.spawn(f, 5)
    g3 = gevent.spawn(f, 5)
    g1.join()
    g2.join()
    g3.join()

    运行结果

    <Greenlet at 0x7fa70ffa1c30: f(5)> 0
    <Greenlet at 0x7fa70ffa1870: f(5)> 0
    <Greenlet at 0x7fa70ffa1eb0: f(5)> 0
    <Greenlet at 0x7fa70ffa1c30: f(5)> 1
    <Greenlet at 0x7fa70ffa1870: f(5)> 1
    <Greenlet at 0x7fa70ffa1eb0: f(5)> 1
    <Greenlet at 0x7fa70ffa1c30: f(5)> 2
    <Greenlet at 0x7fa70ffa1870: f(5)> 2
    <Greenlet at 0x7fa70ffa1eb0: f(5)> 2
    <Greenlet at 0x7fa70ffa1c30: f(5)> 3
    <Greenlet at 0x7fa70ffa1870: f(5)> 3
    <Greenlet at 0x7fa70ffa1eb0: f(5)> 3
    <Greenlet at 0x7fa70ffa1c30: f(5)> 4
    <Greenlet at 0x7fa70ffa1870: f(5)> 4
    <Greenlet at 0x7fa70ffa1eb0: f(5)> 4

    3. 给程序打补丁

    from gevent import monkey
    import gevent
    import random
    import time
    
    # 有耗时操作时需要
    monkey.patch_all()  # 将程序中用到的耗时操作的代码,换为gevent中自己实现的模块
    
    def coroutine_work(coroutine_name):
        for i in range(10):
            print(coroutine_name, i)
            time.sleep(random.random())
    
    gevent.joinall([
            gevent.spawn(coroutine_work, "work1"),
            gevent.spawn(coroutine_work, "work2")
    ])

    运行结果

    work1 0
    work2 0
    work1 1
    work1 2
    work1 3
    work2 1
    work1 4
    work2 2
    work1 5
    work2 3
    work1 6
    work1 7
    work1 8
    work2 4
    work2 5
    work1 9
    work2 6
    work2 7
    work2 8
    work2 9
  • 相关阅读:
    android Camera 如何判断当前使用的摄像头是前置还是后置
    Unity3D中调用外接摄像头,并保存为图片文件
    Android Camera 使用小结
    Android开发之初识Camera图像采集
    android studio 常用快捷键
    Windows下虚拟机安装Mac OS X —– VM12安装Mac OS X 10.11
    unity调android ios 浏览器 uniwebview2.1使用
    unity语言本地化插件 I2 Location2.5.6使用简单记录
    Unity中内嵌网页插件UniWebView使用总结
    ugui mask失效
  • 原文地址:https://www.cnblogs.com/yuqiangli0616/p/10135932.html
Copyright © 2020-2023  润新知