用gevent(协程)实现多任务

1,078 阅读2分钟

gevent实现多任务

gevent是Python的一个模块,可以以协程的方式实现多任务的功能。

gevent协程实现多任务的原理是:在遇到延迟或者等待的步奏,会让线程去另外的协程里面执行任务,直到原来的任务不再延迟或等待。

协程是单线程。

一、简单的演示

使用gevent模块的spawn方法可以创建一个协程,让我们来是以下:

import gevent
import time

def dance():
    for i in range(3):
        print('……dance……')
		# 延迟1秒钟
        time.sleep(1)

def sing():
    for i in range(3):
        print('……sing……')
		# 延迟1秒钟
        time.sleep(1)

# 使用spawn方法创建协程并指定函数名
g_dance = gevent.spawn(dance)
g_sing = gevent.spawn(sing)
# 将主线程设置为等待协程,否则主线程直接结束
g_dance.join()
g_sing.join()

看看这段代码输出了什么:

……dance……
……dance……
……dance……
……sing……
……sing……
……sing……

这样看的话,该代码还是按照一个个函数运行完,并没有完成多任务,这是怎么回事呢?

其实,gevent要求我们使用它自定的sleep方法而不是time的。实际上,gevent要求全部延迟操作都使用gevent内定义的方法。

看看改进后的代码:

import gevent
import time

def dance():
    for i in range(3):
        print('……dance……')
		# 改为gevent的sllep方法
        gevent.sleep(1)


def sing():
    for i in range(3):
        print('……sing……')
		# 改为gevent的sllep方法
        gevent.sleep(1)


g_dance = gevent.spawn(dance)
g_sing = gevent.spawn(sing)
g_dance.join()
g_sing.join()

运行结果如下,成功实现了多任务:

……dance……
……sing……
……dance……
……sing……
……dance……
……sing……

二、monkey实现延迟操作转换

那么我们岂不是需要将所有延迟操作一一改为gevent,那也太麻烦了吧!

别担心,gevent模块内置的monkey可以自动将所以延迟操作替换成gevent自身的,所以就不要特别的去写gevent的延迟方法啦。

看看改进的代码:

import gevent
import time
# 导入gevent里的monkey
from gevent import monkey

# 使用monkey的patch_all方法
monkey.patch_all()

def dance():
    for i in range(3):
        print('……dance……')
		# 这里只要写回原来的延迟方式就好了
        time.sleep(1)

def sing():
    for i in range(3):
        print('……sing……')
        time.sleep(1)

g_dance = gevent.spawn(dance)
g_sing = gevent.spawn(sing)
g_dance.join()
g_sing.join()

输出结果如下,完成多任务:

……dance……
……sing……
……dance……
……sing……
……dance……
……sing……

三、joinall批量启动join方法

除此之外,gevent还提供了joinall()方法,可以让我们方便的启动协程的join方法,而不必要针对每一个协程写一个join。

进一步更新代码:

import gevent
import time
from gevent import monkey

monkey.patch_all()

def dance():
    for i in range(3):
        print('……dance……')
        time.sleep(1)


def sing():
    for i in range(3):
        print('……sing……')
        time.sleep(1)

# 以列表格式将协程放到join_all方法中
gevent.joinall([gevent.spawn(dance),
                 gevent.spawn(sing)])

总结

gevent可以帮助我们用协程的方法实现多任务。

gevent适用于那些常常需要等待或者延迟的操作,否则程序还是会像单任务一样将函数逐个运行。