【问题标题】:Why number of greenlets running is higher than the actual number of created greenlets. 1 additional greenlet is running synchronously为什么运行的greenlets数量高于实际创建的greenlets数量。 1 个额外的 greenlet 正在同步运行
【发布时间】:2017-09-03 18:15:58
【问题描述】:

首先,理想情况下,以下代码应该同步运行 3 个 greenlets,但它会异步运行所有 3 个 greenlets。然而奇怪的事情是不管你有多少个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 怎么会出现两次?

【问题讨论】:

  • 您能否更明确地说明您实际看到的具体观察结果,以及它们与您的预期有何不同? (对为什么你期望你所做的行为也不会造成伤害的一些解释。
  • 从上面的编辑中我的问题更清楚了吗?
  • 这很有帮助,因为它清楚地描述了你当前的行为——但仍然缺少解释为什么你期望相反/不同的行为。
  • apps 在模块中创建了 3 个 greenlet 对象(任务),但是当它们稍后运行时(run()),它首先使三个任务同时运行,但在第一个任务之后完成它再次运行第二个任务。如果执行了 3 个任务而不是 4 个任务,这似乎更合乎逻辑。

标签: python gevent greenlets


【解决方案1】:

当您调用spawn() 时,Greenlets 已经安排好进行调用。直接调用 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 -- 你会注意到它在 before 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-05-27
    • 2018-10-16
    • 2013-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-18
    • 1970-01-01
    相关资源
    最近更新 更多