我有一个生产者和许多消费者的应用程序,以及一个传达它们的队列。
消费者应该从队列中收集一些数据,比方说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中实现此目的的最快方法是什么?
答案 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;围绕处理数据进行构建,但它们对他没用,甚至没有 睡眠任务 。