在 Python 中,threading.Thread 如何产生剩余的量程?

发布于 2024-07-17 17:23:25 字数 524 浏览 3 评论 0原文

我有一个正在轮询硬件的线程。

while not hardware_is_ready():
    pass
process_data_from_hardware()

但还有其他线程(和进程!)可能有事情要做。 如果是这样,我不想在每隔一条指令检查硬件时消耗CPU。 自从我处理线程以来已经有一段时间了,当我处理线程时,它不是Python,但我相信大多数线程库都有一个yield函数或允许线程告诉调度程序的东西“给其他线程一个机会。”

while not hardware_is_ready():
    threading.yield()          # This function doesn't exist.
process_data_from_hardware()

但我在线程文档中找不到任何类似的参考。 Python 确实有一个 yield 语句,但我很确定那完全是另一回事(与生成器有关)。

这里正确的做法是什么?

I've got a thread that's polling a piece of hardware.

while not hardware_is_ready():
    pass
process_data_from_hardware()

But there are other threads (and processes!) that might have things to do. If so, I don't want to burn up cpu checking the hardware every other instruction. It's been a while since I've dealt with threading, and when I did it wasn't Python, but I believe most threading libraries have a yield function or something that allows a thread to tell the scheduler "Give the other threads a chance."

while not hardware_is_ready():
    threading.yield()          # This function doesn't exist.
process_data_from_hardware()

But I can't find any reference to something like this in the threading documentation. Python does have a yield statement, but I'm pretty sure that's something else entirely (to do with generators).

What's the correct thing to do here?

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

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

发布评论

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

评论(4

懒的傷心 2024-07-24 17:23:25

time.sleep(0) 足以产生控制——无需使用正 epsilon。 事实上,time.sleep(0) 的意思是“屈服于任何其他可能准备好的线程”。

time.sleep(0) is sufficient to yield control -- no need to use a positive epsilon. Indeed, time.sleep(0) MEANS "yield to whatever other thread may be ready".

深居我梦 2024-07-24 17:23:25

阅读全局解释器锁 (GIL)。

例如: http://jessenoller.com /2009/02/01/python-threads-and-the-global-interpreter-lock/

另外:http://www.pyzine.com/Issue001/Section_Articles/article_ThreadingGlobalInterpreter.html

如果您必须执行忙等待(例如轮询设备),请在代码中执行此操作)。

time.sleep( 0.0001 )

这将让位于线程调度程序。

另外,我在 http://homepage 中收集了一些注释和参考文献。 mac.com/s_lott/iblog/architecture/C551260341/E20081031204203/index.html

Read up on the Global Interpreter Lock (GIL).

For example: http://jessenoller.com/2009/02/01/python-threads-and-the-global-interpreter-lock/

Also: http://www.pyzine.com/Issue001/Section_Articles/article_ThreadingGlobalInterpreter.html

Do this in your code if you must do Busy Waiting (e.g. polling a device).

time.sleep( 0.0001 )

This will yield to the thread scheduler.

Also, I collected some notes and references in http://homepage.mac.com/s_lott/iblog/architecture/C551260341/E20081031204203/index.html

转身泪倾城 2024-07-24 17:23:25

为什么 time.sleep(0) 中的产量可能不够:

我遇到了类似的问题,最终 time.sleep(0) 并非在所有情况下都有效,而 <代码> time.sleep(0.0001)有效。
就我而言,我使用标准的 vanilla cpython - 可以在 python.org 上找到。
查看 C 代码中 sleep 函数的实现,可以发现 sleep(0) 的调用和 sleep(something_other_than_null) 的调用之间存在微小差异。

查看 timemodule.c 中的 pysleep 你会看到在第一种情况下

if (ul_millis == 0 || !_PyOS_IsMainThread()) {
  Py_BEGIN_ALLOW_THREADS
  Sleep(ul_millis);
  Py_END_ALLOW_THREADS
  break;
}

被称为。 “允许线程”释放 GIL,在这种情况下 Sleep(0) 相当于 std::this_thread::yield(),之后 GIL 再次被声明。
在处理非零值的代码中,除了实际的睡眠/等待之外,还有对 PyErr_CheckSignals - 如其文档中所述“检查信号是否已发送到进程,如果是,则调用相应的信号处理程序”。 这可以解释为什么在某些情况下使用硬件时 time.sleep(0) 是不够的。 所以这可能是 cpython 实现方面的一个失误。 这就是为什么 time.sleep(0.0001) 神奇地起作用。

Why the yield in time.sleep(0) might not be enough:

I had a similar problem and ultimately time.sleep(0) did not work in all cases whereas time.sleep(0.0001) worked.
In my case I use the standard vanilla cpython - which can be found at python.org.
Looking at the implementation of the sleep function in the C code there is a tiny difference between a call of the sleep(0) and sleep(something_other_than_null).

Looking at pysleep in timemodule.c you will see that in the first case

if (ul_millis == 0 || !_PyOS_IsMainThread()) {
  Py_BEGIN_ALLOW_THREADS
  Sleep(ul_millis);
  Py_END_ALLOW_THREADS
  break;
}

is called. The "allow threads" releases the GIL, Sleep(0) in that case is equivalent to std::this_thread::yield(), after that the GIL is claimed again.
In the code that deals with a non-zero value, apart from the actual sleep/wait there is an additional call to PyErr_CheckSignals - which as stated in its documentation "checks whether a signal has been sent to the processes and if so, invokes the corresponding signal handler". That would explain why in some cases when working with hardware a time.sleep(0) is not enough. So this might be a slip on cpython implementation side. And that is why time.sleep(0.0001) magically works.

孤芳又自赏 2024-07-24 17:23:25

如果您在 *nix 上执行此操作,您可能会发现 select 库很有用。 Kamaela 还有一些您可能会觉得有用的组件,但可能需要进行一些范式更改。

If you're doing this on *nix, you might find the select library useful. Kamaela also has a few components you may find useful, but it may require a bit of a paradigm change.

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