python并发之协程

发布时间:2019-09-16 07:25:22编辑:auto阅读(1575)

    概念

    协程,又称微线程。英文名Coroutine。
    子程序,或者称为函数,在所有语言中都是层级调用,比如A调用B,B在执行过程中又调用了C,C执行完毕返回,B执行完毕返回,最后是A执行完毕。所以子程序调用是通过栈实现的,一个线程就是执行一个子程序。

    协程不同于线程,线程是抢占式的调度,而协程是协同式的调度,协程需要自己做调度。
    子程序调用总是一个入口,一次返回,调用顺序是明确的。而协程的调用和子程序不同。协程看上去也是子程序,但执行过程中,在子程序内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行。

    协程优势是极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。用来执行协程多任务非常合适。

    协程没有线程的安全问题。一个进程可以同时存在多个协程,但是只有一个协程是激活的,而且协程的激活和休眠又程序员通过编程来控制,而不是操作系统控制的。
    因为协程是一个线程中执行,那怎么利用多核CPU呢?最简单的方法是多进程+协程,既充分利用多核,又充分发挥协程的高效率,可获得极高的性能。

    Python对协程的支持是通过generator实现的。在generator中,我们不但可以通过for循环来迭代,还可以不断调用next()函数获取由yield语句返回的下一个值。但是Python的yield不但可以返回一个值,它还可以接收调用者发出的参数。

    使用

    用协程来解决生产者消费者问题。

    # coding: utf-8
    
    
    def consumer():
        r = ''
        while 1:
            n = yield r
            if not n:
                break
    
            print 'consumer receive msg: %s' % n
            r = '%s OK' % n
    
    
    def produce():
        c = consumer()
        c.send(None)
    
        n = 0
        while n < 3:
            n += 1
            print 'produce send msg: %s' % n
            r = c.send(n)
            print 'consumer return msg: %s' % r
    
        c.close()
    
    produce()
    

    执行结果

    produce send msg: 1
    consumer receive msg: 1
    consumer return msg: 1 OK
    produce send msg: 2
    consumer receive msg: 2
    consumer return msg: 2 OK
    produce send msg: 3
    consumer receive msg: 3
    consumer return msg: 3 OK

    执行过程分析:
    1. consumer函数是一个generator。
    2. c.send(None)其实等价于next(c),第一次执行时其实只执行到n = yield r就停止了,然后把r的值返回给调用者。
    3. yield r是一个表达式,通过send(msg)被赋值,而send(msg)是有返回值的,返回值为:下一个yield r表达式的参数,即为r。
    4. produce一旦生产了东西,通过c.send(n)切换到consumer执行。consumer通过yield拿到消息,处理,又通过yield把结果传回。也就是说,c.send(1) 不但会给 c 传送一个数据,它还会等着下次 yield 从 c 中返回一个数据,它是有返回值的,一去一回才算完,拿到了返回的数据(200 OK)才继续下面执行。
    5. 整个流程无锁,由一个线程执行,produce和consumer协作完成任务,所以称为“协程”,而非线程的抢占式多任务。

    小结

    TODO

关键字

上一篇: Python字体颜色设置

下一篇: Python操作串口