zoukankan      html  css  js  c++  java
  • python-多任务编程05-协程(coroutine)

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

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

    通过yield实现基础协程

    yield的特点就是能够执行方法函数时,暂停执行,然后再继续往下执行,这样就能够实现方法的切换执行

    import time
    
    
    def dancing():
        for i in range(5):
            print('正在跳舞。。。。%d' % i)
            yield
            time.sleep(0.1)
    
    
    def singing():
        for i in range(5):
            print('正在唱歌。。。。%d' % i)
            yield
            time.sleep(0.1)
    
    
    def main():
        dance = dancing()
        sing = singing()
        for i in range(5):
            next(dance)
            next(sing)
            time.sleep(0.1)
    
    
    if __name__ == '__main__':
        main()

    运行结果为:

     通过greenlet实现协程

    python中的greenlet模块对yield进行封装,从而使得切换任务变的更加简单,使用前先安装:pip install greenlet

    greenlet中先创建对象,然后调用switch()方法开始执行程序

    import time
    from greenlet import greenlet
    
    
    def dancing():
        for i in range(10):
            print('正在跳舞。。。。。%d' % i)
            sing.switch()
            time.sleep(0.1)
    
    
    def singing():
        for i in range(10):
            print('正在唱歌。。。。。%d' % i)
            dance.switch()
            time.sleep(0.1)
    
    
    # 创建全局greenlet对象
    dance = greenlet(dancing)
    sing = greenlet(singing)
    
    
    def main():
        # 调用执行dance
        print('开始执行dance')
        dance.switch()
    
    
    if __name__ == '__main__':
        main()

    运行结果为:

     通过gevent实现协程

    greenlet已经实现了协程,但是需要手动通过调用switch进行切换,而gevent模块比greenlet更强大的并且能够自动切换任务。

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

    使用前先安装:pip install gevent

    gevent的基础使用案例

    1.普通的耗时操作写法需要转化为gevent模块中的耗时操作,如time.sleep转化为gevent.sleep

    2.使用join()开始执行对象中对应的方法并等待方法执行完成

    import gevent
    import time
    
    
    def dancing(n):
        for i in range(n):
            print('正在跳舞...%d' % i)
            # time.sleep(0.2)
            # 普通的耗时操作,如time.sleep、socket.recv()、socket.connect()等
            # 这些代码需要手动转换为gevent模块中对应的方法,才能被gevent认为是耗时操作
            # 当gevent遇到了认可的耗时操作后,就会自动切换通过gevent创建的对象
            # 若没有遇到耗时操作,则按顺序执行gevent对象
            gevent.sleep(0.5)
    
    
    def singing(n):
        for i in range(n):
            print('正在唱歌...%d' % i)
            # time.sleep(0.2)
            gevent.sleep(0.5)
    
    
    def main():
        print('--------main开始-------')
        # 创建对象,这时并没有执行方法里面的代码
        dance = gevent.spawn(dancing, 5)
        sing = gevent.spawn(singing, 6)
        # join()开始执行对象中对应的方法并等待方法执行完成
        # 在执行方法的过程中,遇到耗时操作,则自动会切换执行gevent对象中的其他方法。
        dance.join()
        sing.join()
        print('-------main结束--------')
    
    
    if __name__ == '__main__':
        main()

    运行结果为:

     gevent的常用简洁写法

    1.导入gevent中的monkey,可以将程序中的普通耗时操作转换为gevent中认可的耗时操作

    2.使用gevent.joinall让程序更加简洁

    import gevent
    from gevent import monkey
    import time
    
    # 有耗时操作时,需要执行这句话
    # 能将普通的耗时操作转换为gevent中的耗时操作,这样就不用手动把耗时操作全都替换成gevent中对应的耗时操作了
    monkey.patch_all()
    
    
    def work(name, num):
        for i in range(num):
            print('%s正在执行。。。。%d' % (name, i))
            time.sleep(0.2)
    
    
    def main():
        dance = gevent.spawn(work, '小明', 5)
        sing = gevent.spawn(work, '小花', 6)
        gevent.joinall([dance, sing])
    
    
    if __name__ == '__main__':
        main()

    运行结果为:

  • 相关阅读:
    设置Tomcat根目录
    使用Servlet Filter做Login checking
    Javac命令一次编译一个目录下的所有java文件
    Java ArrayList操作
    Java 读Properties
    Java文件读写
    Servlet Listener
    Servlet连接数据库
    Servlet Filter 3
    Servlet Filter 2
  • 原文地址:https://www.cnblogs.com/gcxblogs/p/12951463.html
Copyright © 2011-2022 走看看