【问题标题】:Why does Python's queue.Queue.get() permit returning early from timeouts?为什么 Python 的 queue.Queue.get() 允许从超时中提前返回?
【发布时间】:2011-06-07 06:15:10
【问题描述】:

更新:这个问题是基于 Queue.get() 实际行为方式的错误心理模型,这是由一些稍微模棱两可的文档引起的,但主要是由 timedelta.total_seconds() 的错误手动实现引起的。当我试图证明原始答案不正确时,我发现了这个错误。现在timedelta.total_seconds() 由 Python 提供(自 2.7 起),我将继续使用它。

很抱歉给您带来了困惑。


这不是“为什么我的代码无法运行?”问题,而是“这个设计决策背后的动机是什么?”

从 2.3 开始,Python 的 queue 模块包含一个带有 get 方法的 Queue 类,该方法接受一个超时参数。这是手册中的部分:

Queue.get([block[, timeout]])
从队列中移除并返回一个项目。如果可选的 args 块为真并且超时为无(默认值),则在必要时阻止,直到项目可用。如果 timeout 是一个正数,它会阻塞 最多 秒 timeout 秒,如果在那段时间内没有可用的项目,则会引发 Empty 异常。 [...]

(强调我的)

请注意,它可能会引发 Empty 异常即使它没有达到超时时间。事实上,我在 Ubuntu(但不是 Windows)上看到了这种行为。它只是提前了一点,它对我的​​代码产生了轻微的影响 - 不过我可以围绕它编写代码。

大多数阻塞超时都采用最小超时,这在非实时操作系统(包括 Windows 和 Linux)上是有意义的。无法保证操作系统会在任何给定的截止日期前切换到您的进程或线程。

但是,这需要 最大 超时。谁能解释一下这个设计决策如何有意义?

【问题讨论】:

    标签: python real-time


    【解决方案1】:

    我认为您误解了文档。这并不是说它可能会在不到timeout 秒后引发Empty 异常,而是说它最多会阻塞timeout 秒。如果它可以满足get,它可能会阻塞小于这个值。

    我知道你说你看到它提早了Empty,但老实说,这听起来像是一个错误,或者你依赖的准确性超出了系统所能提供的范围。 (看起来,为了遵守规范的确切措辞,实现应该将timeout down 舍入到它的计时器的分辨率,而不是像你想要的那样向上。)

    【讨论】:

      【解决方案2】:

      除非您正在进行实时编程,否则正确的程序必须假定任何超时值都是指导性的,因此您在哪一边出错并不重要。请注意,queue 确实 等待 至少 如果队列保持为空则超时(通过查看代码确认,这基本上是一个循环,如果 remaining (时间) 小于 0)。但是,如果在此期间将项目放入队列,它会更早返回。

      你期待这种行为:

      [0] (Thread) A calls Queue.get(True, 10)
      [0] B waits 9 seconds
      [9] B does something on X
      [11] A destroys X
      

      但一个有效的时间表也是如此:

      [0] (Thread) A calls Queue.get(True, 10)
      [0] B waits 9 seconds
      [9] Operating system is busy for 2 seconds
      [11] A gets picked by the OS, destroys X    
      [12] B does something on X
      

      您需要修复程序以独立于选择哪个线程的实际时间来工作。

      【讨论】:

      • +1 用于检查 Queue.Queue 背后的代码。这动摇了我对自己职位的信心。我应该自己做的。然而,虽然我显然很困惑,但这并不是我所遇到的困惑。我声称线程 A 在 [9.999] 唤醒,队列中没有任何内容。我现在看到由于实现错误,我睡了 9.999 而不是 10。
      【解决方案3】:

      Queue.get 中肯定存在错误,至少在 python 2.6.6 中是这样。 在 posix 上,queue.get(timeout=1) 似乎几乎立即退出(引发 Empty 异常),而 queue.get(timeout=2) 工作正常。

      我正在使用带有并发线程的单个队列 *get*ing 在上面...

      【讨论】:

        猜你喜欢
        • 2021-04-01
        • 2022-01-06
        • 1970-01-01
        • 1970-01-01
        • 2021-05-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多