5

我正在接受 Gevents(用于异步功能的 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教程的一部分。

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

     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
4

2 回答 2

9

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

在教程代码的异步部分,任务以随机顺序完成的主要原因是它们已经随机休眠了一段时间

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

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

但是,最后,如果您细心,您会注意到它们以您可能期望的相反顺序完成。

为什么是这样?

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

由于这是每个函数所做的唯一“工作”,它具有使您的代码再次同步的效果。

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

Gevent 提供了一个非阻塞版本的time.sleep()- gevent.sleep()。您会注意到这就是教程代码使用的内容。您还可以修改该功能。目前,您通常更喜欢只使用 gevent 的版本。

查看已monkey_patch修补的事物列表,应该可以很好地但非详尽地概述通常阻塞的正常事物的类型。

编辑:您的工作创建循环中的逻辑也不正确。

更好的是——

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

或者更简单地说,只是:

jobs = [gevent.spawn(mytime, i) for i in x]
于 2012-02-07T15:10:44.497 回答
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
于 2012-02-07T15:17:18.863 回答