47

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

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声明,但我很确定这完全是另一回事(与生成器有关)。

在这里做什么是正确的?

4

4 回答 4

81

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

于 2009-04-26T04:39:41.263 回答
14

阅读全局解释器锁 (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中收集了一些笔记和参考资料

于 2009-04-24T22:31:16.740 回答
4

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

于 2009-04-25T01:37:31.847 回答
2

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

我遇到了类似的问题,最终time.sleep(0)在所有情况下都没有工作time.sleep(0.0001)。在我的例子中,我使用标准的 vanilla cpython——可以在 python.org 找到。sleep(0)查看 C 代码中 sleep 函数的实现,调用和之间存在细微差别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的额外调用- 如其文档中所述,“检查信号是否已发送到进程,如果是,则调用相应的信号处理程序”。这可以解释为什么在某些情况下使用硬件 atime.sleep(0)是不够的。所以这可能是 cpython 实现方面的一个失误。这就是为什么time.sleep(0.0001)神奇地起作用的原因。

于 2021-05-04T05:31:56.773 回答