python 协程

简介:

线程和进程都是抢占式的,即系统调配,有一定时间片;

而协程则是程序自己安排执行顺序,可以主动让出CPU,系统是不知道的,在lua等脚本语言中都有机制。

 

使用协程的几种方法:

yield

注意协程关键是程序自己安排执行顺序,函数可以通过yield让出执行权。

import time

def A():
    while 1:
        print('-----A-----')
        time.sleep(1)
        yield()

def B():
    while 1:
        print('-----B-----')
        time.sleep(1)
        next(a)

a = A()
B()

 

greenlet

greenlet是个第三方库,pip可以直接安装,封装了一些接口,但仍然是阻塞的。

from greenlet import greenlet
import time

def A():
    while 1:
        print('------A-------')
        time.sleep(1)
        g2.switch()

def B():
    while 1:
        print('------B-------')
        time.sleep(1)
        g1.switch()

g1 = greenlet(A)  # 创建协程g1
g2 = greenlet(B)

g1.switch()  # 跳转至协程g1

 

gevent

基于greenlet再次封装的框架,其实还有其他框架。

关键是有个monkey补丁,可以实现非阻塞IO。

import gevent
from gevent import monkey  # 若不使用monkey补丁,则阻塞将使整个程序阻塞!
monkey.patch_all()
import time

def A():
    while 1:
        print('------A-------')
        gevent.sleep(1)

def B():
    while 1:
        print('------B-------')
        time.sleep(5)   # 关键在这里,这里的睡眠原本将阻塞进程,但由于有monkey补丁,这里变为非阻塞。
        gevent.sleep(1)

g1 = gevent.spawn(A) # 创建一个协程
g2 = gevent.spawn(B)
g1.join()  # 等待协程执行结束
g2.join()

 

关键:

  • 导入monkey补丁不可以gevent.monkey.patch_all(),因为monkey模块是个gevent子模块,文件包含关系;
  • gevent.sleep(1),这里将放弃CPU控制权1秒,这里将保证至少1秒,睡眠期间即使没有协程占有CPU,睡眠协程也不会占有;
  • monkey补丁将修改Python底层的api,这其实对于出问题时找bug会造成一定影响,所以patch_all的参数,将允许你替换一部分IO,将其改成非阻塞

 

在IO密集的情况下,协程效率还是非常高的。但注意,协程并不能发挥多核的作用,实际还是单线程的。

posted on 2017-12-21 17:43  willaty  阅读(166)  评论(0编辑  收藏  举报

导航