为什么Python的multiprocessing模块没有Timer类?

6 投票
2 回答
8578 浏览
提问于 2025-04-18 17:13

所以,threading模块里有一个Timer类,它是从Thread类继承来的,用来重复执行一些任务。

我在想,为什么multiprocessing模块没有类似的TimedProcess类呢?比如说,它可以从Process类继承,用来重复执行一些任务。

其实是可以写这样的定时进程的,我也写过一个,但我还是很好奇。难道我漏掉了什么吗?

2 个回答

5

这个问题比较开放,直接的答案可能不太有用。

不过我们可以试着做一些有根据的猜测。

pyprocessing* 没有这个功能。为什么呢?可能是因为它不是特别有用。

几乎任何需要定时器的复杂应用都需要多个定时器、循环定时器、相对快速的定时器等等。为每个定时事件启动一个新线程是个糟糕的主意。

那么,为什么它会出现在 threading 模块里呢?

其实,对于一些简单的应用,它是可以有用的。比如在一个单进程的应用中,添加 threading 只是为了启动一个 Timer 来给主线程发送信号,如果主线程迷失了方向,可以打断它,这样做其实也不算过分。但这和 multiprocessing 没什么关系。

另外,threading 是一个设计得比较适合用作示例代码的模块,而不仅仅是一个库——这在它刚被添加时尤其明显。这就是为什么 文档 会链接到 源代码。而 Timer 是个很好的示例代码——它的功能和工作原理都很明显,很难想象还有什么比这更简单的代码可以用来演示如何使用同步对象。不过,你不需要在两个地方都有这段代码来作为示例,而且也没有什么额外的、特定于多进程的内容需要演示。

最后,Itamar Shtull-Trauring 想要这个功能,做了工作并提出了建议,没人能提出好的理由反对它被包含进来;大概 pyprocessing 从来没有发生过这样的事情。**

在 2.6/3.0 版本规划期间,PEP 371pyprocessing 整合进了标准库的 multiprocessing 模块。这是一项相当大的工作,而且做得有点匆忙,特别是因为他们还承担了将 threading 中的名称改为符合 PEP8 标准的任务,这样就不需要为了让 pyprocessing 的名称与 threading 中的不标准名称匹配而重新命名,等到 threading 在一两年后修复时又重新改回来。所以,尽管尽可能地让它成为 threading 的替代品是一个次要目标,但我猜没有人做过全面的调查来确保这一点。

从那以后,可能是没人注意到它缺失并提出建议,或者没有人提出足够有说服力的理由,或者没有人实际去做这件事。如果你认为应该添加这个功能,并且能为你的观点辩护,可以创建一个bug或者写信给 python-ideas,附上你的实现代码,并签署 PSF 贡献者协议,这样可能会让你名留青史。:)

* 不幸的是,我找不到关于 pyprocessing 的好的历史链接。源代码库已经不存在了,贡献者们转而维护标准库的 multiprocessing 模块和 PyPI 的 multiprocessing 回退版本,甚至这个项目也大部分被 billiard 取代,而在这段时间里,一个新的、无关的项目接管了原来的名字……

** 注意,在 问题 #428326 中,Timer 首次被建议时,超过一半的理由是它是个很好的示例代码。

10

自己实现这个功能其实很简单:

from multiprocessing import Process, Event


class Timer(Process):
    def __init__(self, interval, function, args=[], kwargs={}):
        super(Timer, self).__init__()
        self.interval = interval
        self.function = function
        self.args = args
        self.kwargs = kwargs
        self.finished = Event()

    def cancel(self):
        """Stop the timer if it hasn't finished yet"""
        self.finished.set()

    def run(self):
        self.finished.wait(self.interval)
        if not self.finished.is_set():
            self.function(*self.args, **self.kwargs)
        self.finished.set()

我不太明白为什么标准库里没有这个功能。也许是因为它用得不太多吧?

撰写回答