为什么Python的queue.Queue.get()允许从超时中提前返回?

发布于 2024-11-14 14:32:26 字数 849 浏览 0 评论 0原文

更新:这个问题基于 Queue.get() 实际行为的错误心理模型,这是由一些稍微含糊的文档引起的,但主要是由 timedelta.total_seconds()< 的有缺陷的手动实现引起的/代码>。我在试图证明原始答案不正确时发现了这个错误。既然 Python 提供了 timedelta.total_seconds()(自 2.7 起),我将开始使用它。

抱歉造成混乱。


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

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

Queue.get([block[, timeout]])
从队列中删除并返回一个项目。如果可选参数块为 true 并且超时为 None(默认值),则根据需要进行阻止,直到有项目可用。如果超时是正数,则它会阻止最多超时秒,并且如果在该时间内没有可用的项目,则会引发空异常。 [...]

(强调我的)

请注意,即使尚未达到超时,它也可能会引发空异常。事实上,我在 Ubuntu 上看到了这种行为(但在 Windows 上没有)。它的退出有点早,并且对我的代码产生了轻微的影响 - 不过我可以围绕它进行编码。

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

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

UPDATE: This question is based on a faulty mental model of how Queue.get() was actually behaving, which was caused by some slightly ambiguous documentation but mainly by a buggy, hand-rolled implementation of timedelta.total_seconds(). I discovered this bug when trying to prove that the original answers where incorrect. Now that timedelta.total_seconds() is provided by Python (since 2.7), I will move to use that.

Sorry for the confusion.


This isn't a "Why does my code not run?" question, but a "What is the motivation behind this design decision?"

Since 2.3, Python's queue module contains a Queue class with a get method, that takes a timeout parameter. Here's the section from the manual:

Queue.get([block[, timeout]])
Remove and return an item from the queue. If optional args block is true and timeout is None (the default), block if necessary until an item is available. If timeout is a positive number, it blocks at most timeout seconds and raises the Empty exception if no item was available within that time. [...]

(Emphasis mine)

Note that it may raise an Empty exception even if it hasn't reached the timeout. In fact, I am seeing that behaviour on Ubuntu (but not Windows). It is bailing just a little early and it has had minor consequences on my code - I can code around it though.

Most blocking timeouts take a minimum timeout, which makes sense on a non-real-time OS, including Windows and Linux. There is no guarantee that the OS will context switch to your process or thread by any given deadline.

However, this one takes a maximum timeout. Can anyone explain how this design decision might make sense?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

待"谢繁草 2024-11-21 14:32:26

我认为您误解了文档。它并不是说它可能会在不到 timeout 秒后引发 Empty 异常,而是说它最多会阻塞 timeout 秒。如果它可以满足 get 的要求,那么它可能会阻塞得更少。

我知道你是说你看到它很早就引发了Empty,但老实说,这听起来要么是一个错误,要么你依赖的准确性比系统所能提供的更高。 (看起来,为了遵守规范的确切措辞,实现应该将 timeout down 舍入到其计时器的分辨率,而不是像您希望的那样向上舍入.)

I think you are misinterpreting the documentation. It isn't saying it might raise the Empty exception after less than timeout seconds, it is saying it will block for at most timeout seconds. It might block for less than that, if it can satisfy the get.

I realize you are saying you see it raising Empty early, but honestly, that sounds like either a bug, or that you are relying on more accuracy than the system can provide. (It does seem as though, to obey the exact wording of the specification, an implementation should round timeout down to the resolution of its timer rather than up as you seem to desire.)

歌枕肩 2024-11-21 14:32:26

除非您正在进行实时编程,否则正确的程序必须假设任何超时值都是一个指导,因此无论您在哪一边出错都没关系。请注意,如果队列保持为空,queue等待至少超时(通过查看代码来确认,这基本上是一个循环,如果剩余(时间)小于 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

您需要修复程序,使其独立于何时选择哪个线程的实际时间而工作。

Unless you're doing real-time programming, a correct program must assume any timeout value is a guidance anyway, so it does not matter on which side you error. Note that queue does wait for at least the timeout if the queue stays empty (Confirmed by a look in the code which is basically a loop that exits if remaining (time) is less than 0). It returns earlier if an item is put into the queue in the meantime, though.

You're expecting this behavior:

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

But a valid schedule would be as well:

[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

You need to fix the program to work independent of the actual timing of which thread is picked when.

呢古 2024-11-21 14:32:26

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

我使用的是带有并发线程的单个队列*get*ing...

There is definitely a bug in Queue.get, at least in python 2.6.6.
On posix a queue.get(timeout=1) seems to exit (raising the Empty exception) almost immediately, whereas queue.get(timeout=2) is working fine.

I was using a single queue with concurrent threads *get*ing on it...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文