【问题标题】:Why is `gevent.spawn` different than a monkeypatched `threading.Thread()`?为什么`gevent.spawn`与猴子补丁`threading.Thread()`不同?
【发布时间】:2012-10-23 22:43:25
【问题描述】:

在仔细检查 threading.Condition 是否正确修补了猴子修补程序时,我注意到猴子修补程序 threading.Thread(…).start() 的行为与 gevent.spawn(…) 不同。

考虑:

from gevent import monkey; monkey.patch_all()
from threading import Thread, Condition
import gevent

cv = Condition()

def wait_on_cv(x):
    cv.acquire()
    cv.wait()
    print "Here:", x
    cv.release()

# XXX: This code yields "This operation would block forever" when joining the first thread
threads = [ gevent.spawn(wait_on_cv, x) for x in range(10) ]

"""
# XXX: This code, which seems semantically similar, works correctly
threads = [ Thread(target=wait_on_cv, args=(x, )) for x in range(10) ]
for t in threads:
    t.start()
"""

cv.acquire()
cv.notify_all()
print "Notified!"
cv.release()

for x, thread in enumerate(threads):
    print "Joining", x
    thread.join()

注意,特别是两个以XXX开头的cmets。

当使用第一行(带有gevent.spawn)时,第一个thread.join() 会引发异常:

通知! 加入 0 回溯(最近一次通话最后): 文件“foo.py”,第 30 行,在 线程.join() 文件“…/gevent/greenlet.py”,第 291 行,加入 结果 = self.parent.switch() 文件“…/gevent/hub.py”,第 381 行,在交换机中 返回 greenlet.switch(self) gevent.hub.LoopExit:此操作将永远阻塞

但是,Thread(…).start()(第二个区块),一切正常。

为什么会这样? gevent.spawn()Thread(…).start() 有什么区别?

【问题讨论】:

    标签: python multithreading gevent


    【解决方案1】:

    在您的代码中发生的情况是,您在 threads 列表中创建的 greenlets 还没有机会执行,因为 gevent 不会触发上下文切换,直到您可以在代码中使用gevent.sleep() 等或通过调用阻塞例如的函数来隐式执行此操作。 semaphore.wait() 或者通过 yield 等等...,看看你可以在 cv.wait() 之前插入一个 print 并看到它只在 cv.notify_all() 被调用之后被调用:

    def wait_on_cv(x):
        cv.acquire()
        print 'acquired ', x
        cv.wait()
        ....
    

    因此,一个简单的代码修复方法是在创建 greenlets 列表后插入将触发上下文切换的内容,例如:

    ...
    threads = [ gevent.spawn(wait_on_cv, x) for x in range(10) ]
    gevent.sleep()  # Trigger a context switch
    ...
    

    注意:我还是 gevent 的新手,所以我不知道这是否是正确的做法:)

    这样所有 greenlets 都有机会被执行,并且每个人都会在调用 cv.wait() 时触发上下文切换,同时它们会 将它们自己注册到条件服务员,以便在调用 cv.notify_all() 时 将通知所有 greenlets

    HTH,

    【讨论】:

      猜你喜欢
      • 2019-09-07
      • 2010-09-29
      • 2016-09-01
      • 2012-09-16
      • 2012-12-18
      • 2020-01-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多