【问题标题】:How does a threading.Thread yield the rest of its quantum in Python?threading.Thread 如何在 Python 中产生剩余的量子?
【发布时间】:2010-10-21 17:30:03
【问题描述】:

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

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

这里的正确做法是什么?

【问题讨论】:

    标签: python multithreading yield


    【解决方案1】:

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

    【讨论】:

    • 这是否记录在某处?我认为这可能是真的——我在其他语言中见过它——但我在 Python 文档中找不到它的提及。
    • 例如,docs.python.org/library/sched.html "在每个事件运行后,delayfunc 也将被调用,参数为 0,以允许其他线程有机会在多线程应用程序中运行。" (delayfunc 通常是 time.sleep 这里)。我同意如果在模块时间更直接地记录它会更好;-)
    • Windows 用户:设置为 0 对我不起作用,time.sleep(0.0001) 起作用。
    • 这对我来说不适用于带有 python 3.6.4 的 Windows 7。
    【解决方案2】:

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

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

    还有:http://www.pyzine.com/Issue001/Section_Articles/article_ThreadingGlobalInterpreter.html

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

    time.sleep( 0.0001 )
    

    这将让给线程调度程序。

    另外,我在http://homepage.mac.com/s_lott/iblog/architecture/C551260341/E20081031204203/index.html收集了一些笔记和参考

    【讨论】:

    • 我不是专家,但我读过一些关于 GIL 的文章。你能给我一个提示,这与这个问题特别相关吗?我现在会选择time.sleep(epsilon),但这有点不满意,不是吗?我没有特别想睡觉的时间间隔。
    • 如果您的硬件无法发送中断,这是唯一的解决方案。
    • 不使用time.sleep(),Python如何进行抢先让步?在什么条件下会产生收益?
    • 三个链接似乎都坏了。
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

      为什么time.sleep(0) 的收益可能不够:

      我遇到了类似的问题,最终time.sleep(0) 并非在所有情况下都有效,而time.sleep(0.0001) 有效。 在我的例子中,我使用标准的 vanilla cpython——可以在 python.org 找到。 查看 C 代码中 sleep 函数的实现,sleep(0)sleep(something_other_than_null) 的调用之间存在细微差别。

      查看pysleep in timemodule.c,您会看到第一种情况

      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) 神奇地起作用的原因。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-01-18
        • 1970-01-01
        • 1970-01-01
        • 2021-12-22
        • 1970-01-01
        • 2014-09-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多