【问题标题】:Python multiprocessing.Process calls join by itselfPython multiprocessing.Process 自行调用 join
【发布时间】:2018-03-01 13:33:28
【问题描述】:

我有这个代码:

class ExtendedProcess(multiprocessing.Process):
    def __init__(self):
        super(ExtendedProcess, self).__init__()
        self.stop_request = multiprocessing.Event()

    def join(self, timeout=None):
        logging.debug("stop request received")
        self.stop_request.set()
        super(ExtendedProcess, self).join(timeout)

    def run(self):
        logging.debug("process has started")
        while not self.stop_request.is_set():
            print "doing something"
        logging.debug("proc is stopping")

当我在进程上调用 start() 时,它应该永远运行,因为 self.stop_request() 没有设置。几毫秒后,join() 被自己调用并中断运行。到底是怎么回事!?为什么join是自己调用的?

此外,当我启动调试器并逐行运行时,它突然工作正常......我错过了什么?

好的,感谢 ely 的回答让我想到了原因:

存在竞争条件 -

  1. 新进程已创建...
  2. 当它自己启动并即将运行 logging.debug("process has started") 时,主函数会结束。
  3. main 函数调用 sys exit 和 on sys exit python 调用所有已完成的进程以使用 join() 关闭。
  4. 因为进程实际上并没有点击“while not self.stop_request.is_set()”,所以调用了连接并调用了“self.stop_request.set()”。现在 stop_request.is_set 和代码关闭。

【问题讨论】:

    标签: python python-2.7 python-multiprocessing


    【解决方案1】:

    正如更新的问题中提到的,这是因为竞争条件。下面我举了一个初始示例,突出显示了一个简单的竞争条件,其中竞争是针对整个程序退出的,但这也可能是由其他类型的范围退出或涉及您的进程的其他一般竞争条件引起的。

    我复制了你的类定义并添加了一些“主要”代码来运行它,这是我的完整清单:

    import logging
    import multiprocessing
    import time
    
    
    class ExtendedProcess(multiprocessing.Process):
        def __init__(self):
            super(ExtendedProcess, self).__init__()
            self.stop_request = multiprocessing.Event()
    
        def join(self, timeout=None):
            logging.debug("stop request received")
            self.stop_request.set()
            super(ExtendedProcess, self).join(timeout)
    
        def run(self):
            logging.debug("process has started")
            while not self.stop_request.is_set():
                print("doing something")
                time.sleep(1)
            logging.debug("proc is stopping")
    
    
    if __name__ == "__main__":
        p = ExtendedProcess()
        p.start()
        while True:
            pass
    

    上面的代码清单使用 Python 2.7.11 和 3.6.4 按预期运行。它无限循环,进程永远不会终止:

    ely@eschaton:~/programming$ python extended_process.py 
    doing something
    doing something
    doing something
    doing something
    doing something
    ... and so on
    

    但是,如果我在我的主要部分中使用此代码,它会立即退出(如预期的那样):

    if __name__ == "__main__":
        p = ExtendedProcess()
        p.start()
    

    这退出是因为解释器到达程序的末尾,这反过来又会触发自动销毁 p 对象,因为它超出了整个程序的范围。

    请注意,这也可以解释为什么它在调试器中对您有用。那是一个交互式编程会话,因此在您启动p 后,调试器环境允许您等待并检查它......它不会被自动销毁,除非您以某种方式在某个范围内调用它,而在单步执行时退出调试器。

    也只是为了验证连接行为,我也尝试了这个主块:

    if __name__ == "__main__":
        log = logging.getLogger()
        log.setLevel(logging.DEBUG)
        p = ExtendedProcess()
        p.start()
        st_time = time.time()
        while time.time() - st_time < 5:
            pass
        p.join()
        print("Finished!")
    

    它按预期工作:

    ely@eschaton:~/programming$ python extended_process.py 
    DEBUG:root:process has started
    doing something
    doing something
    doing something
    doing something
    doing something
    DEBUG:root:stop request received
    DEBUG:root:proc is stopping
    Finished!
    

    【讨论】:

    • NVM 我的评论...我想我明白了
    • 谢谢,有了你的回答,我发现这是一个竞争条件。我已经编辑了我的问题。我会将您的答案标记为正确,但也请指出我问题中的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-19
    • 2011-05-16
    • 1970-01-01
    • 2017-12-30
    • 1970-01-01
    • 2011-09-01
    相关资源
    最近更新 更多