一尘不染

队列上有多重队列

go

如何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中实现?

更新0

根据tux21b答案中给出的链接,所需的队列类型具有以下属性:

  • 多生产者/多消费者队列(MPMC)
  • 提供每个生产者FIFO / LIFO
  • 当队列为空/完整的消费者/生产者被阻止时

此外,渠道可能会被阻塞,生产者将阻塞,直到消费者取回该物品为止。我不确定Python的Queue是否可以做到这一点。


阅读 279

收藏
2020-07-02

共1个答案

一尘不染

生产者-
消费者队列有许多不同的实现,例如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的有限线程功能强大得多。

2020-07-02