我有一个程序包含一个生产者和两个慢消费者,我想用协同程序重写它,以便每个消费者只处理最后一个值(即跳过在处理旧值时生成的新值)为它生成的(我使用了线程和threading.Queue()
但是在put()
上使用了块,导致队列在大多数时间都是满的。)< / p>
阅读answer to this question后,我决定使用asyncio.Event
和asyncio.Queue
。我写了这个原型程序:
import asyncio
async def l(event, q):
h = 1
while True:
# ready
event.set()
# get value to process
a = await q.get()
# process it
print(a * h)
h *= 2
async def m(event, q):
i = 1
while True:
# pass element to consumer, when it's ready
if event.is_set():
await q.put(i)
event.clear()
# produce value
i += 1
el = asyncio.get_event_loop()
ev = asyncio.Event()
qu = asyncio.Queue(2)
tasks = [
asyncio.ensure_future(l(ev, qu)),
asyncio.ensure_future(m(ev, qu))
]
el.run_until_complete(asyncio.gather(*tasks))
el.close()
我注意到l
行上的q.get()
协程阻止,并且没有打印任何内容。
在两者中添加asyncio.sleep()
之后,我的预期效果正常(我得 1,11,21,... ):
import asyncio
import time
async def l(event, q):
h = 1
a = 1
event.set()
while True:
# await asyncio.sleep(1)
a = await q.get()
# process it
await asyncio.sleep(1)
print(a * h)
event.set()
async def m(event, q):
i = 1
while True:
# pass element to consumer, when it's ready
if event.is_set():
await q.put(i)
event.clear()
await asyncio.sleep(0.1)
# produce value
i += 1
el = asyncio.get_event_loop()
ev = asyncio.Event()
qu = asyncio.Queue(2)
tasks = [
asyncio.ensure_future(l(ev, qu)),
asyncio.ensure_future(m(ev, qu))
]
el.run_until_complete(asyncio.gather(*tasks))
el.close()
......但是我没有它就在寻找解决方案。
为什么会这样?我该如何解决?我想我不能从await l()
拨打m
,因为他们都有状态(在原始程序中,第一个使用PyGame绘制解决方案,第二个绘图结果)。
答案 0 :(得分:1)
代码无法正常工作,因为运行m函数的任务永远不会停止。在event.is_set()== False的情况下,任务将继续递增i。由于此任务永远不会挂起,因此永远不会调用任务运行函数l。因此,您需要一种方法来暂停任务运行功能m。暂停的一种方法是等待另一个协程,这就是为什么asyncio.sleep按预期工作的原因。
我认为以下代码可以按预期工作。 LeakyQueue将确保消费者只处理生产者的最后一个值。由于复杂性非常对称,消费者将消耗生产者产生的所有价值。如果增加delay参数,则可以模拟消费者仅处理生产者创建的最后一个值。
batch.end()