我正在运行一个Python程序,它使用多处理模块来生成一些工作线程。使用Pool.map
这些消化文件列表。
在某些时候,我想停止一切并让脚本死掉。
通常命令行中的Ctrl+C
可以完成此操作。但是,在这种情况下,我认为只会中断其中一名工人,并产生一名新工人。
因此,我最终在有问题的流程ID上运行ps aux | grep -i python
并使用kill -9
。
是否有更好的方法让中断信号使一切停止?
答案 0 :(得分:22)
SIGQUIT( Ctrl + \ )即使在Python 2.x下也会终止所有进程。
你也可以更新到Python 3.x,这种行为(只有孩子获得信号)似乎已得到修复。
答案 1 :(得分:4)
不幸的是,在Python 2.x中,对于这个问题确实没有一个好的解决方案。我所知道的最佳解决方法是使用pool.map_async(...).get(timeout=<large number>)
而不是pool.map
。问题是pool.map
调用threading.Condition.wait()
,由于某种原因,它不能被Python 2.x中的Ctrl + C中断(它在Python 3中有效)。当您使用map_async()
时,它会调用threading.Condition.wait(timeout=<large number>)
,最终会执行忙等待循环,可以被Ctrl + C中断。
亲自试试:
c = threading.Condition()
try:
c.acquire()
c.wait() # You won't be able to interrupt this
except KeyboardInterrupt:
print("Caught it")
c = threading.Condition()
try:
c.acquire()
c.wait(timeout=100) # You CAN interrupt this
except KeyboardInterrupt:
print("Caught it")
因此,要使map
来电中断,请执行以下操作:
if __name__ == "__main__":
p = multiprocessing.Pool()
try:
p.map_async(func, iterable).get(timeout=10000000)
except KeyboardInterrupt:
print("Caught it")
# Optionally try to gracefully shut down the worker processes here.
p.close()
# DON'T join the pool. You'll end up hanging.
另请注意,正如phihag所指出的,这个问题在Python 3.4中得到修复(可能在3.x中更早)。
答案 2 :(得分:3)
有两种方法。第一种方法是使用
将线程标记为守护进程在线程中,
myThread.setDaemon(true)
多处理中的,
myThread.daemon = True
标记为守护程序的所有线程将以主线程终止。这不是正确的方法,因为它不允许线程清理
下一个方法是使用try-catch监听KeyboardInterrupt
,然后使用.join()这样的线程。
try:
myThread = MyThread()
except KeyboardInterrupt:
myThread.join()
如果您的线程处于循环中,您可以使用诸如boolean的条件,将其设置为false,并且当条件为false时,它将执行清理。
class MyThread(Threading.thread):
def __init__(self):
self.alive=True
def run(self):
while self.alive:
#do stuff
#cleanup goes here, outside the loop
try:
myThread = MyThread()
except KeyboardInterrupt:
myThread.alive = False
myThread.join()
答案 3 :(得分:0)
我发现在这种情况下使用python信号库效果很好。初始化池时,可以将信号处理程序传递给每个线程,以便在主线程获得键盘中断时设置默认行为。
如果你真的只想让一切都死掉,赶上主线程中的键盘中断异常,并调用pool.terminate()。