使用Gevents异步生成函数

时间:2012-02-07 05:35:23

标签: python asynchronous gevent

我正在接受Gevents(用于asych功能的python库)并编写了一个非常小的程序来了解它是如何工作的,但结果非常令人费解。 以下是代码

import gevent 
import time 


def mytime(t):
    time.sleep(t)
    print " i have slept for ",t,"secs"

x = range (0,10)
x.reverse()

for i in x :
    jobs = [ gevent.spawn(mytime , i) ] 
gevent.joinall(jobs)

输出无论我跑多少次,我都会

 i have slept for  9 secs
 i have slept for  8 secs
 i have slept for  7 secs
 i have slept for  6 secs
 i have slept for  5 secs
 i have slept for  4 secs
 i have slept for  3 secs
 i have slept for  2 secs
 i have slept for  1 secs
 i have slept for  0 secs

有一个类似的例子,作为gevent tutorials的一部分呈现。

异步功能非常明显。我所做的就是在代码中添加一个睡眠功能。输出不应该是这样的吗?

     i have slept for  6 secs
     i have slept for  8 secs
     i have slept for  5 secs
     i have slept for  9 secs
     i have slept for  7 secs
     i have slept for  0 secs
     i have slept for  3 secs
     i have slept for  2 secs
     i have slept for  1 secs
     i have slept for  4 secs

2 个答案:

答案 0 :(得分:9)

您对该教程的反应似乎表明您错过了它试图展示的部分内容。

在教程代码的异步部分中,任务以随机顺序完成的主要原因是因为他们在一段随机时间内睡眠

他们仍然在代码的同步部分中随机休眠一段时间,但由于每个任务在前一个任务完成后执行,它们也按顺序完成。

您和异步教程的代码之间的区别在于您睡眠了一段预定的时间,因此您的任务应该在以后以预定的方式完成这段时间。

但是,最后,如果你是观察者,你会注意到他们按照你可能期望的相反顺序完成。

为什么会这样?

因为您已在代码中插入了阻止代码。阻止代码为time.sleep()。当某些东西被阻塞时,这意味着它已经为自己抓取了所有执行,并且在它完成之前不会让任何其他东西(例如,你的其他greenlet)运行。

由于这是每个函数唯一的“工作”,它可以使代码再次同步。

在编写这些类型的程序时,您希望尽可能使阻塞代码不存在。您必须始终注意编写可能阻塞的代码,并且您通常希望尽可能频繁地找到非阻塞代码。

Gevent提供time.sleep() - gevent.sleep()的非阻止版本。您将注意到教程代码使用的内容。你也可以monkey patch这个功能。 目前,您通常更喜欢使用gevent的版本。

查看monkey_patch补丁的列表,应该为您提供一个很好但非详尽的概述,通常会阻止正常事物的类型。

编辑:你的作业创建循环中也有不正确的逻辑。

更好的是 -

jobs = []
for i in x:
    jobs.append(gevent.spawn(mytime, i))

或更简单地说,只是:

jobs = [gevent.spawn(mytime, i) for i in x]

答案 1 :(得分:4)

您应该在此处使用gevent.sleep()代替time.sleep()来获得正确的输出:

import gevent

def mytime(t):
    gevent.sleep(t) #NOTE: not time.sleep()
    print " i have slept for ",t,"secs"

jobs = [gevent.spawn(mytime, i) for i in reversed(range(10))]
gevent.joinall(jobs)

输出

 i have slept for  0 secs
 i have slept for  1 secs
 i have slept for  2 secs
 i have slept for  3 secs
 i have slept for  4 secs
 i have slept for  5 secs
 i have slept for  6 secs
 i have slept for  7 secs
 i have slept for  8 secs
 i have slept for  9 secs

较大的i后期mytime(i)会产生输出,无论产生的顺序为mytime(i)

如果您首先点击它,可以使用time.sleep()

import gevent.monkey
gevent.monkey.patch_time()

import time