用于具有哨兵的循环发生器

时间:2017-07-03 11:18:33

标签: python generator

我有一个生产者和许多消费者的应用程序,以及一个传达它们的队列。 消费者应该从队列中收集一些数据,比方说qsize()/number_of_consumers,但是当sentinel出现时它必须停止工作。

我有这样的代码:

frame = 0
elems_max = 10
while frame is not None:
    frames = []
    for _ in range(elems_max):
        frame = queue_in.get()
        if frame:
            frames.append(frame)
        else:
            break
   process_data(frames)

正如您所看到的,None是此队列的标记,当它出现时,我不想打破我的工作过程。我还希望获得更多的数据处理元素。

在python 3.5中实现此目的的最快方法是什么?

2 个答案:

答案 0 :(得分:2)

我了解您在遇到while时想要打破外部None

您可以在True必须执行时保留while的布尔变量,在{#}}停止时保留False

这看起来像这样:

frame = 0
elems_max = 10
running = True
while running and frame is not None:
    frames = []
    for _ in range(elems_max):
        frame = queue_in.get()
        if frame is not None:
            frames.append(frame)
        else:
            running = False
            break
   process_data(frames)

break指令会破坏内部for,但不会破坏外部while。 但是,将running设置为False后,while循环将停止。

根据您的评论。

不可能在理解中包含break语句,也不可能在else子句中包含{/ 1}}语句:

frames = [f for i in range(elems_max)如果queue_in.get()不是None else break]

但是,您可以构建列表,然后在None

之后删除所有元素
frames = [queue_in.get() for _ in range(elems_max)]

try:
    noneId = frames.find(None)
    frames = frames[:noneId]
except ValueError:
    pass

这不是很有效,因为可能会在frames中附加许多元素。 我更喜欢手工构造,以避免这种危险。

基于发电机的另一种解决方案。 这可能不是您所期望的,但语法相当简单,所以您可能会喜欢它。

我们的想法是将数据的获取包装在生成器中,这会打破None值:

def queue_data_generator(queue, count):
    for _ in range(count):
        item = queue.get()
        if item is None:
            raise StopIteration
        else:
            yield item

然后,实例化这个生成器,并简单地迭代它:

g = queue_data_generator(queue_in, elems_max)
frames = [frame for frame in g]

frames列表将包含queue_in中包含的所有帧,直到第一个None。 用法相当简单,但您必须通过定义生成器来设置它。 我觉得它很优雅。

答案 1 :(得分:0)

我会做下一个(有点伪代码):

class CInputQueue:
    def get(self, preffered_N):
        # do sync stuff
        # take <= N elements (you can do kinda balance the load)
        # or throw exception
        raise Exception("No data, no work, no life.")

elems_max = 10
try:
    while True:
       process_data(queue_in.get(elems_max))
except:
    None # break 

我认为数据处理花费的时间比0毫秒多,所以我使用异常。我知道它不是okey使用流量控制的异常,但对于worker它确实是例外。他的生活&#34;围绕处理数据进行构建,但它们对他没用,甚至没有 睡眠任务