简体   繁体   English

Python multiprocessing.Process 自行调用 join

[英]Python multiprocessing.Process calls join by itself

I have this code:我有这个代码:

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")

When I call start() on the process it should be running forever, since self.stop_request() is not set.当我在进程上调用 start() 时,它应该永远运行,因为 self.stop_request() 没有设置。 After some miliseconds join() is being called by itself and breaking run.几毫秒后, join() 被自身调用并中断运行。 What is going on!?到底是怎么回事!? why is join being called by itself?为什么join被自己调用?

Moreover, when I start a debugger and go line by line it's suddenly working fine.... What am I missing?此外,当我启动调试器并逐行运行时,它突然工作正常......我错过了什么?

OK, thanks to ely's answer the reason hit me:好的,多亏了 ely 的回答,我才明白原因:

There is a race condition -有一个竞争条件 -

  1. new process created...新进程创建...
  2. as it's starting itself and about to run logging.debug("process has started") the main function hits end.当它自己启动并即将运行 logging.debug("process has started") 时,主函数结束了。
  3. main function calls sys exit and on sys exit python calls for all finished processes to close with join(). main 函数调用 sys exit 并且在 sys exit python 调用所有已完成的进程以使用 join() 关闭。
  4. since the process didn't actually hit "while not self.stop_request.is_set()" join is called and "self.stop_request.set()".由于该过程实际上并未命中“while not self.stop_request.is_set()” join 被调用并“self.stop_request.set()”。 Now stop_request.is_set and the code closes.现在 stop_request.is_set 和代码关闭。

As mentioned in the updated question, this is because of a race condition.正如更新的问题中提到的,这是因为竞争条件。 Below I put an initial example highlighting a simplistic race condition where the race is against the overall program exit, but this could also be caused by other types of scope exits or other general race conditions involving your process.下面我放了一个初始示例,突出显示了一个简单的竞争条件,其中竞争与整个程序退出有关,但这也可能是由其他类型的范围退出或涉及您的进程的其他一般竞争条件引起的。

I copied your class definition and added some "main" code to run it, here's my full listing:我复制了您的类定义并添加了一些“主要”代码来运行它,这是我的完整清单:

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

The above code listing runs as expected for me using both Python 2.7.11 and 3.6.4.上面的代码清单在我使用 Python 2.7.11 和 3.6.4 时按预期运行。 It loops infinitely and the process never terminates:它无限循环,过程永不终止:

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

However, if I instead use this code in my main section, it exits right away (as expected):但是,如果我在我的主要部分中使用此代码,它会立即退出(如预期的那样):

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

This exits because the interpreter reaches the end of the program, which in turn triggers automatically destroying the p object as it goes out of scope of the whole program.这退出是因为解释器到达程序的末尾,当p对象超出整个程序的范围时,它反过来触发自动销毁p对象。

Note this could also explain why it works for you in the debugger.请注意,这也可以解释为什么它在调试器中对您有用。 That is an interactive programming session, so after you start p , the debugger environment allows you to wait around and inspect it ... it would not be automatically destroyed unless you somehow invoked it within some scope that is exited while stepping through the debugger.这是一个交互式编程会话,因此在您启动p ,调试器环境允许您等待并检查它……除非您以某种方式在逐步调试调试器时退出的某个范围内以某种方式调用它,否则它不会自动销毁。

Just to verify the join behavior too, I also tried with this main block:只是为了验证连接行为,我还尝试了这个主块:

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!")

and it works as expected:它按预期工作:

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!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM