为什么运行的greenlet数量高于实际创建的greenlet数量。 1个额外的greenlet同步运行

时间:2017-04-08 11:52:35

标签: python gevent greenlets

首先,理想情况下,以下代码应同步运行3个greenlet,而不是异步运行所有3个greenlet。然而,奇怪的是,无论您拥有多少个greenlet,它都会为第二个greenlet启动一个额外的同步过程。我不是要问这个问题的解决方法,只是因为我想了解背后的原因。

import gevent
import time

def func(i):
    t = time.time()
    print('func %s started at %s' % (i, t))
    secs = 5
    statement = "after %s secs" % secs
    gevent.sleep(secs)
    print('func %s stopped in %s secs' % (i, (time.time() - t)))

apps = [gevent.Greenlet.spawn(func, i) for i in range(3)]

[app.run() for app in apps]

以下是示例标准输出:

func 0 started at 1491859273.2895772
func 1 started at 1491859273.2898045
func 2 started at 1491859273.2899446
func 0 stopped in 5.0095603466033936 secs
func 1 started at 1491859278.2993205
func 1 stopped in 5.0163233280181885 secs
func 2 stopped in 5.019707918167114 secs
func 1 stopped in 5.009198188781738 secs

func 1 started如何发生两次?

1 个答案:

答案 0 :(得分:0)

当您调用spawn()时,已调度Greenlet进行调用。直接调用run()不是公开记录的API的一部分,其效果未定义。然后,观察为什么当前行为的任何描述都需要超出所记录的API到实现细节。

使用gevent.joinall()等待已安排的作业完成。

apps = [gevent.Greenlet.spawn(func, i) for i in range(3)]
gevent.joinall(apps)

正确收益:

func 0 started at 1491921603.6
func 1 started at 1491921603.6
func 2 started at 1491921603.6
func 0 stopped in 5.00121307373 secs
func 1 stopped in 5.00118613243 secs
func 2 stopped in 5.0011780262 secs

现在,让我们深入研究一下这种未定义的行为,并了解它很容易改变发布版本或系统到系统。

特别是Greenlet 1运行两次的原因是控制的主要线程首次合作产生的意外。您可以通过在第一次调用run()之前显式地生成来更改此行为:

print "=== About to spawn greenlets..."
apps = [gevent.Greenlet.spawn(func, i) for i in range(3)]
print "=== All greenlets spawned; yielding..."
gevent.sleep(0)
print "=== Calling a duplicate run() invocation on each"
result = [app.run() for app in apps]

有了这个改变,它首先启动的是greenlet 0 - 你会注意到之前 <{strong> run()从来没有打过电话:

=== About to spawn greenlets...
=== All greenlets spawned; yielding...
func 0 started at 1491921486.57
func 1 started at 1491921486.57
func 2 started at 1491921486.57
=== Calling a duplicate run() invocation on each
func 0 started at 1491921486.57
func 0 stopped in 5.00335502625 secs
func 1 stopped in 5.00336790085 secs
func 2 stopped in 5.0033519268 secs
func 0 stopped in 5.0033428669 secs