gpt4 book ai didi

Python:进程被杀死后多次打印到控制台

转载 作者:太空宇宙 更新时间:2023-11-04 03:52:25 34 4
gpt4 key购买 nike

我有以下 python3 程序,它创建了许多工作进程并在我按下 ctrl-c 时杀死它们。在向子进程发送 SIGTERM 之前,master 在控制台上打印一行 print('[W] aghhh ... %d' % self.pid)。问题是对于给定的进程,该行输出不止一次。像这样(实际控制台输出):

[W] aghhh ... 15773
[W] aghhh ... 15773
[W] aghhh ... 15774
[W] aghhh ... 15773
[W] aghhh ... 15774
[W] aghhh ... 15775
[W] aghhh ... 15776

问题:这怎么可能?杀死子进程的正确方法是什么?

代码:

import os
import time
import signal
import sys


class ChildProcess:
def __init__(self, m):
self.pid = None
self.ttl = 10
self.master = m
self.pipe_in = None
self.pipe_out = None

def hey(self):
self.ttl -= 1
self.pipe_out.write('Hello worker %d\n' % self.pid)
self.pipe_out.flush()

def tell_me(self):
msg = self.pipe_in.readline()
print('[M] Worker process %d says: %s' % (self.pid, msg), end='')

def live(self):
r1, w1 = os.pipe()
r2, w2 = os.pipe()
pid = os.fork()
self.pid = pid
if pid:
print('[M] Created worker process %d' % pid)
os.close(w1)
os.close(r2)
self.pipe_in = os.fdopen(r1, 'rt')
self.pipe_out = os.fdopen(w2, 'wt')
self.master.add(self)
else:
print('[W] Worker process ready to rock')
os.close(r1)
os.close(w2)
wr = os.fdopen(w1, 'wt')
reader = os.fdopen(r2)
while True:
wr.write('Hello Master\n')
wr.flush()
msg = reader.readline()
print('[W] Master says %s' % msg, end='')

def die(self):
print('[W] aghhh ... %d' % self.pid)
os.kill(self.pid, signal.SIGTERM)


class Master:
def __init__(self):
self.workers = []

def add(self, worker):
self.workers.append(worker)

def rulez(self, nbr=2):
for i in range(nbr):
worker = ChildProcess(self)
worker.live()
while True:
for w in self.workers:
w.tell_me()
time.sleep(1)
w.hey()

def reap(self):
for w in self.workers:
w.die()


if __name__ == '__main__':
master = Master()

try:
master.rulez(3)
except KeyboardInterrupt:
master.reap()

最佳答案

这是因为子进程正在执行与父进程相同的代码。所以对于子进程,当他们执行 while True: wr.write('Hello Master\n') ... 时,如果他们在被父进程杀死之前收到 SIG_INT,他们将提高KeyboardInterrupt 到调用方法,即 master.rulez(3)

所以,是的,实际上在 master.rulez(3) 中将引发多达 4 个 KeyboardInterrupt。您可以通过在 except KeyboardInterrupt 中打印一些内容来确认这一点,或者更好地打印 len(self.workers)。这将产生这样的东西:

...[W] Master says Hello worker 769^C321[W] aghhh ... 7690[W] aghhh ... 769[W] aghhh ... 769[W] aghhh ... 770[W] aghhh ... 770[W] aghhh ... 771

Note that each child is forked when the master had probably forked other children, and so there are some other children in the 'self.workers'. So for the first child, this will be empty, the second child this would be 1, the third child this would be 2.

Visualisation of your code (for two workers):

Master||ChildProcess1 (init)|+---------------------+ (fork)|                     |self.workers.add(1)   While True: ...|                     ||                     (KeyboardInterrupt)|                     master.reap()ChildProcess2 (init)  (exit)|+---------------------+ (fork) <---- This copied self.workers also, which |                     |              already contains ChildProcess1self.workers.add(2)   While True: ... while True: ...       |(KeyboardInterrupt)   (KeyboardInterrupt)master.reap()         master.reap()ChildProcess1.die()   ChildProcess1.die()ChildProcess2.die()   (exit)(exit)

To prevent the child from continuing execution of master.rulez(3), you can catch the KeyboardInterrupt in the child process, and then raise sys.exit() there (or it can kill itself using os.kill() also)

Code:

import os
import time
import signal
import sys


class ChildProcess:
def __init__(self, m):
self.pid = None
self.ttl = 10
self.master = m
self.pipe_in = None
self.pipe_out = None

def hey(self):
self.ttl -= 1
self.pipe_out.write('Hello worker %d\n' % self.pid)
self.pipe_out.flush()

def tell_me(self):
msg = self.pipe_in.readline()
print '[M] Worker process %d says: %s' % (self.pid, msg),

def live(self):
r1, w1 = os.pipe()
r2, w2 = os.pipe()
pid = os.fork()
self.pid = pid
if pid:
print('[M] Created worker process %d' % pid)
os.close(w1)
os.close(r2)
self.pipe_in = os.fdopen(r1, 'rt')
self.pipe_out = os.fdopen(w2, 'wt')
self.master.add(self)
else:
print('[W] Worker process ready to rock')
os.close(r1)
os.close(w2)
wr = os.fdopen(w1, 'wt')
reader = os.fdopen(r2)
try:
while True:
wr.write('Hello Master\n')
wr.flush()
msg = reader.readline()
print('[W] Master says %s' % msg),
except KeyboardInterrupt:
sys.exit()

def die(self):
print('[W] aghhh ... %d' % self.pid)
os.kill(self.pid, signal.SIGTERM)


class Master:
def __init__(self):
self.workers = []

def add(self, worker):
self.workers.append(worker)

def rulez(self, nbr=2):
for i in range(nbr):
worker = ChildProcess(self)
worker.live()
while True:
for w in self.workers:
w.tell_me()
time.sleep(1)
w.hey()

def reap(self):
print len(self.workers)
for w in self.workers:
w.die()


if __name__ == '__main__':
master = Master()

try:
master.rulez(4)
except KeyboardInterrupt:
master.reap()

结果:

...[W] Master says Hello worker 779^C3[W] aghhh ... 779[W] aghhh ... 780[W] aghhh ... 781

关于Python:进程被杀死后多次打印到控制台,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20622889/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com