Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/285.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 通信队列结束_Python_Multithreading_Queue - Fatal编程技术网

Python 通信队列结束

Python 通信队列结束,python,multithreading,queue,Python,Multithreading,Queue,我正在学习使用队列模块,对于如何让队列使用者线程知道队列已完成,我有点困惑。理想情况下,我希望在使用者线程中使用get(),并在队列标记为“完成”时让它抛出异常。有没有更好的方法来传达这一点,而不是附加一个哨兵值来标记队列中的最后一个项目?队列本身并不具有完成或完成的想法。它们可以无限期地使用。要在完成后关闭它,您确实需要在末尾添加None或其他神奇值,并编写逻辑来检查它,如您所述。理想的方法可能是对队列对象进行子类化 请参阅以了解有关队列的更多信息。哨兵是关闭队列的自然方式,但有几件事需要注意

我正在学习使用队列模块,对于如何让队列使用者线程知道队列已完成,我有点困惑。理想情况下,我希望在使用者线程中使用
get()
,并在队列标记为“完成”时让它抛出异常。有没有更好的方法来传达这一点,而不是附加一个哨兵值来标记队列中的最后一个项目?

队列本身并不具有完成或完成的想法。它们可以无限期地使用。要在完成后关闭它,您确实需要在末尾添加None或其他神奇值,并编写逻辑来检查它,如您所述。理想的方法可能是对队列对象进行子类化


请参阅以了解有关队列的更多信息。

哨兵是关闭队列的自然方式,但有几件事需要注意

首先,请记住,您可能有多个消费者,因此您需要为每个正在运行的消费者发送一次sentinel,并确保每个消费者只使用一个sentinel,以确保每个消费者都收到其关机sentinel

其次,请记住队列定义了一个接口,并且在可能的情况下,代码的行为应该与底层队列无关。您可能有一个PriorityQueue,或者您可能有另一个类公开同一接口并以其他顺序返回值

不幸的是,很难同时处理这两个问题。要处理不同队列的一般情况,正在关闭的使用者必须在收到其关闭哨兵后继续使用值,直到队列为空。这意味着它可能会消耗另一个线程的哨兵。这是Queue接口的一个弱点:它应该有一个
Queue.shutdown
调用,以导致所有使用者都抛出异常,但缺少该调用

因此,在实践中:

  • 如果您确定只使用常规队列,只需为每个线程发送一个哨兵
  • 如果您可能正在使用PriorityQueue,请确保sentinel具有最低优先级

最好的做法是让队列本身通知客户端它已达到“完成”状态。然后,客户机可以采取任何适当的操作

你的建议;检查队列以查看它是否定期执行是非常不可取的。轮询是多线程编程中的一种反模式,您应该始终使用通知

编辑:
因此,您的说法是队列本身知道它是基于某些标准“完成”的,并且需要通知客户端这一事实。我认为您是正确的,最好的方法是在客户端调用get()且队列处于完成状态时抛出。如果您抛出此选项,则不需要在客户端使用sentinel值。在内部,队列可以检测到它以任何方式“完成”,例如,队列为空,其状态设置为“完成”,等等。我认为不需要哨兵值。

队列是FIFO(先进先出)寄存器,因此请记住,消费者可以比生产者更快。当使用者线程检测到队列为空时,通常会执行以下操作之一:

  • 发送到API:切换到下一个线程
  • 发送到API:睡眠几毫秒,然后再次检查队列
  • 发送到API:等待事件(如队列中的新消息)
  • 如果您不希望使用者线程在作业完成后终止,请在队列中输入sentinel值以终止任务。

    original(大部分已更改;请参阅下面的更新) 基于的一些(谢谢!)和其他,我决定卷起
    Queue.Queue
    的后代,它实现了
    close
    方法。它以原语(未打包)的形式提供。我会把这个整理一下,等我有时间的时候再把它打包好。目前,模块仅包含
    CloseableQueue
    类和
    Closed
    异常类。我计划将其扩展到包括
    Queue.LifoQueue
    Queue.PriorityQueue
    的子类

    它目前处于一个相当初步的状态,也就是说,尽管它通过了测试套件,但实际上我还没有在任何方面使用它。您的里程可能会有所不同。我会用激动人心的消息更新这个答案

    CloseableQueue
    类与Glenn的建议有一点不同,关闭队列将阻止未来的
    put
    s,但在队列清空之前不会阻止未来的
    get
    s。这对我来说是最有意义的;似乎清除队列的功能可以作为一个单独的mixin*添加,该mixin*与closeability功能正交。因此,基本上对于
    CloseableQueue
    ,关闭队列表示最后一个元素已被
    put
    。还有一个选项可以通过将
    last=True
    传递到最终的
    put
    调用来实现原子化。队列清空后,对
    put
    的后续调用、对
    get
    的后续调用以及与这些描述匹配的未完成阻止调用将引发
    Closed
    异常

    这在单个生产者为一个或多个消费者生成数据的情况下非常有用,但在消费者等待特定项目或项目集的多重安排中也非常有用。特别是,它没有提供一种方法来确定所有的生产商都已经完成了生产。要实现这一目标,需要提供某种方式来注册制作人(
    .open()
    ?),以及一种方式来表明制作人注册本身已经结束

    建议和/或代码审查是非常受欢迎的。我还没有写过很多并发代码,但希望测试套件足够全面,代码通过测试的事实是一个标志
    $ easy_install CloseableQueue