Python多进程:优雅地终止一个进程

5 投票
3 回答
14705 浏览
提问于 2025-04-30 08:56

这个

import multiprocessing
import schedule


def worker():
     #do some stuff


def sched(argv):
    schedule.every(0.01).minutes.do(worker)          
    while True:
        schedule.run_pending()


processs = []
..
..
p = multiprocessing.Process(target=sched,args)
..
..
processs.append(p)

for p in processs:
    p.terminate()

能优雅地结束一系列进程吗?

如果不能,有什么简单的方法可以做到呢?

我的目的是把配置文件重新加载到内存中,所以我想结束所有子进程,然后再创建新的进程,这样新的进程就能读取新的配置文件。

编辑:我添加了更多代码来说明我在运行一个 while True 循环。

编辑:这是根据 @dano 的 建议 修改后的新代码。

def get_config(self):
        from ConfigParser import SafeConfigParser
..
        return argv

def sched(self, args, event):
#schedule instruction:
        schedule.every(0.01).minutes.do(self.worker,args)
        while not  event.is_set():
                schedule.run_pending()                                                                    

def dispatch_processs(self, conf):
        processs = []
        event = multiprocessing.Event()

        for conf in self.get_config():
                process = multiprocessing.Process(target=self.sched,args=( i for i in conf), kwargs={'event' : event})
                processs.append((process, event)
return processs

def start_process(self, process):
        process.start()

def gracefull_process(self, process):
        process.join()

def main(self):
        while True:
                processs = self.dispatch_processs(self.get_config())
                print ("%s processes running " % len(processs) )

                for process, event in processs:                                                               

                        self.start_process(process)
                        time.sleep(1)
                        event.set()
                        self.gracefull_process(process)

这个代码的好处是,我可以编辑配置文件,进程也会重新加载它的配置。

问题是只有第一个进程在运行,其他的都被忽略了。

编辑:这个建议救了我,使用 while True 在 schedule() 中不是个好主意,所以我改成了 refresh_time

def sched(self, args, event):

    schedule.every(0.01).minutes.do(self.worker,args)
    for i in range(refresh_time):
            schedule.run_pending() 
            time.sleep(1)

def start_processs(self, processs):
        for p,event in processs:
                if not p.is_alive():
                        p.start()
                time.sleep(1)
                event.set()

        self.gracefull_processs(processs)

def gracefull_processs(self, processs):
        for p,event in processs:
                p.join()
        processs = self.dispatch_processs(self.get_config())
        self.start_processs(processs)

def main(self):

        while True:
                processs = self.dispatch_processs(self.get_config())

                self.start_processs(processs)
                break
        print ("Reloading function main")
        self.main()
暂无标签

3 个回答

1

不,根据你自己对“优雅关闭”的定义,这并不会杀掉一个进程,除非你采取一些额外的步骤。

假设你在使用Unix系统(因为你提到了scp),terminate会向子进程发送一个叫做SIGTERM的信号。子进程可以接收到这个信号,并根据这个信号采取相应的行动(比如等scp完成):

import signal

def on_terminate(signum, stack):
    wait_for_current_scp_operation()

signal.signal(signal.SIGTERM, on_terminate)

这里有一个关于处理和发送信号的教程

2

A: 不,.terminate() 和 SIG_* 方法都比较粗暴

如果你想优雅地结束一个进程,就像你帖子里提到的那样,应该有一种“软信号”的方式。这种方式可以让两个端点之间发送和接收智能信号,而不依赖于操作系统的解释(因为操作系统并不了解你应用程序的具体情况和当前正在处理的工作单元的状态)。

在这里输入图片描述 你可以查看关于这种软信号方法的更多信息,链接在这里 >>> https://stackoverflow.com/a/25373416/3666197

7

如果你不介意在 worker 完成所有工作后再停止程序,那么加一个 multiprocessing.Event 来优雅地退出是非常简单的:

import multiprocessing
import schedule


def worker():
     #do some stuff

def sched(argv, event=None):
    schedule.every(0.01).minutes.do(worker)          
    while not event.is_set():  # Run until we're told to shut down.
        schedule.run_pending()

processes = []
..
..
event = multiprocessing.Event()
p = multiprocessing.Process(target=sched,args, kwargs={'event' : event})
..
..
processes.append((p, event))

# Tell all processes to shut down
for _, event in processes:
    event.set()

# Now actually wait for them to shut down
for p, _ in processes:
    p.join()

撰写回答