我正在接受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
答案 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