如何queue.Queue同时在多个对象上“选择” ?
queue.Queue
Golang的频道具有所需的功能:
select { case i1 = <-c1: print("received ", i1, " from c1\n") case c2 <- i2: print("sent ", i2, " to c2\n") case i3, ok := (<-c3): // same as: i3, ok := <-c3 if ok { print("received ", i3, " from c3\n") } else { print("c3 is closed\n") } default: print("no communication\n") }
其中第一个要解除阻塞的通道执行相应的块。如何在Python中实现?
根据tux21b答案中给出的链接,所需的队列类型具有以下属性:
此外,渠道可能会被阻塞,生产者将阻塞,直到消费者取回该物品为止。我不确定Python的Queue是否可以做到这一点。
生产者- 消费者队列有许多不同的实现,例如queue.Queue可用。它们通常具有许多不同的属性,例如DmitryVyukov 在这篇出色的文章中列出的属性。如您所见,可能有超过1万种不同的组合。根据要求,用于这种队列的算法也相差很大。仅扩展现有队列算法以保证其他属性是不可能的,因为这通常需要不同的内部数据结构和不同的算法。
Go的频道提供了相对较高的保证属性,因此这些频道可能适用于许多程序。最困难的要求之一是支持一次读取/阻塞多个通道(select语句),并且如果select语句中可以有多个分支能够继续进行,则要公平地选择一个通道,这样就不会留下任何消息。 。Python的queue.Queue不提供此功能,因此根本无法使用它来存档相同的行为。
因此,如果要继续使用queue.Queue,则需要查找该问题的解决方法。但是,变通办法有其自身的缺点列表,并且较难维护。寻找另一个提供所需功能的生产者- 消费者队列可能是一个更好的主意!无论如何,这是两个可能的解决方法:
轮询
while True: try: i1 = c1.get_nowait() print "received %s from c1" % i1 except queue.Empty: pass try: i2 = c2.get_nowait() print "received %s from c2" % i2 except queue.Empty: pass time.sleep(0.1)
在轮询通道时,这可能会占用大量CPU周期,并且在有很多消息时可能会变慢。将time.sleep()与指数退避时间一起使用(而不是此处显示的恒定0.1秒)可能会大大改善此版本。
单个通知队列
queue_id = notify.get() if queue_id == 1: i1 = c1.get() print "received %s from c1" % i1 elif queue_id == 2: i2 = c2.get() print "received %s from c2" % i2
使用此设置,您必须在发送到c1或c2之后将某些内容发送到通知队列。只要您只有一个这样的通知队列就足够了(即您没有多个“选择”,每个“选择”阻塞在通道的不同子集上),这可能对您有用。
另外,您也可以考虑使用Go。无论如何,Go的goroutines和并发支持比Python的有限线程功能强大得多。