当在greenlet主greenlet除外内调用queue.get时,gevent队列不会引发Empty?

问题描述

我对 gevent 很陌生,我的问题甚至可能很幼稚,但是当我运行以下代码时,我得到队列空异常。

案例 1 有意义

import gevent
from gevent import monkey
monkey.patch_all()

q = gevent.queue.Queue(maxsize=10)

try:
    q.get(timeout=1)
except gevent.queue.Empty:
    print("main greenlet queue empty")

但是如果我运行下面的代码,我不会得到任何超时,代码只是从不调用任何异常,我从不进入异常处理块,实际上代码甚至不会等待 1 秒从队列中获取数据。我只是立即执行显示输出

案例 2

import gevent
from gevent import monkey
monkey.patch_all()

q = gevent.queue.Queue(maxsize=10)

def worker(idx):
    print("worker",idx)
    try:
        q.get(timeout=1)
    except gevent.queue.Empty:
        print("worker",idx,"queue empty")

workers = [gevent.spawn(worker,i) for i in range(1)]

这个输出

worker 0

但是,如果我在主 greenlet 中调用 get 并在 child 和 main greenlet 中调用 queue.get 如下所示,行为现在会恢复正常。

案例 3

import gevent
from gevent import monkey
monkey.patch_all()

q = gevent.queue.Queue(maxsize=10)

def worker(idx):
    print("worker",i) for i in range(1)]

try:
    q.get(timeout=1)
except gevent.queue.Empty:
    print("main greenlet queue empty")

我得到以下输出

worker 0
main greenlet queue empty
worker 0 queue empty

我不明白为什么情况 2 不会引发异常,有人可以向我解释我做错了什么吗?

我正在使用 python 3.7 和 gevent '21.1.2'

解决方法

在您的第二种情况下,您正在启动 greenlets(解释器在此之后退出)。添加 joinall() 会使您的代码等待生成的 greenlets 返回:

q = gevent.queue.Queue(maxsize=10)

def worker(idx):
    print("worker",idx)
    try:
        q.get(timeout=1)
    except gevent.queue.Empty:
        print("worker",idx,"queue empty")


print(q.empty())
workers = [gevent.spawn(worker,i) for i in range(1)]
# waiting for them to finish,works as expected!
gevent.joinall(workers)

出:

True
worker 0
worker 0 queue empty