Python协程

本文主要介绍python协程相关知识。

1.关于协程

线程和进程都是系统帮咱们开辟的,不管是thread还是process他内部都是调用的系统的API,而对于协程来说它和系统毫无关系;
协程不同于线程的是,线程是抢占式的调度,而协程是协同式的调度,也就是说,协程需要自己做调度。

优点:
无需线程上下文切换的开销,协程避免了无意义的调度,由此可以提高性能
无需原子操作锁定及同步的开销
方便切换控制流,简化编程模型
高并发+高扩展性+低成本

2.实现协程

  • yield实现协程

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    def consumer(name):
    print("要开始啃骨头了...")
    while True:
    print("\033[31;1m[consumer] %s\033[0m " % name)
    bone = yield
    print("[%s] 正在啃骨头 %s" % (name, bone))


    def producer(obj1, obj2):
    obj1.send(None) //启动obj1这个生成器,第一次必须用None <==> obj1.__next__()
    obj2.send(None) //启动obj2这个生成器,第一次必须用None <==> obj2.__next__()
    n = 0
    while n < 5:
    n += 1
    print("\033[32;1m[producer]\033[0m 正在生产骨头 %s" % n)
    obj1.send(n)
    obj2.send(n)


    if __name__ == '__main__':
    con1 = consumer("消费者A")
    con2 = consumer("消费者B")
    producer(con1, con2)
  • greenlet实现协程

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    #! /usr/bin/env python
    # -*- coding:utf-8 -*-

    from greenlet import greenlet
    # greenlet 其实就是手动切换;gevent是对greenlet的封装,可以实现自动切换

    def test1():
    print("123")
    gr2.switch() # 切换去执行test2
    print("456")
    gr2.switch() # 切换回test2之前执行到的位置,接着执行

    def test2():
    print("789")
    gr1.switch() # 切换回test1之前执行到的位置,接着执行
    print("666")


    gr1 = greenlet(test1) # 启动一个协程 注意test1不要加()
    gr2 = greenlet(test2) #
    gr1.switch()
  • gevent 实现协程

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    import gevent

    def func1():
    print("func1 running")
    gevent.sleep(2) # 内部函数实现io操作
    print("switch func1")

    def func2():
    print("func2 running")
    gevent.sleep(1)
    print("switch func2")

    def func3():
    print("func3 running")
    gevent.sleep(0)
    print("func3 done..")

    gevent.joinall([gevent.spawn(func1),
    gevent.spawn(func2),
    gevent.spawn(func3),
    ])
---------------- The End ----------------