我正在编写一个简单的线程应用程序,并且将线程设置为daemon
,因为我希望我的程序在KeyboardInterrupt
退出。这样可以很好地工作,并使用python3
可以得到预期的结果,但是python2.7
似乎并不尊重daemon
标志。下面是我的示例代码
if __name__ == '__main__':
try:
threads = [Thread(target=some_func, args=(arg1,arg2)) for _ in range(10)]
for th in threads:
th.daemon=True
th.start()
for th in threads:
th.join()
except KeyboardInterrupt:
sys.exit('Ctrl-c issued by user .. Exiting')
当我在python3
上运行此代码,然后过一会儿按ctrl-c
时,我的程序按预期退出,但是当我用python2.7
运行此代码,然后按ctrl-c
时它永远不会退出,我必须从shell中终止该进程。
我在这里想念什么吗?我还尝试设置threading.Event
,然后在发生KeyboardInterrupt
时清除事件,但即使这样也不起作用
使用python3
,如果我没有join
我的daemon
线程,则它们将在程序完成后退出,并且如果我不将线程标记为{ {1}}而不是daemon
,然后程序继续运行,一旦我按下join
,它就会退出。但这与ctrl-c
编辑#1
我做了一些更深入的研究,看来python2.7
无法捕获python2.7
。这更加奇怪,因为KeyboardInterrupt
可以正常工作,它是一个非线程程序,但是即使线程被标记为KeyboardInterrupt
,也无法捕获线程KeyboardInterrupt
。
所有这些仅在daemon
上发生,并且python2.7
可以正常工作。
答案 0 :(得分:1)
Thread.join
在旧版Python中的工作方式可以静默吞没信号,直到join
完成为止。这包括SIGINT aka KeyboardInterrupt。
作为解决方法,您可以尝试短sleep
或join
。如果您希望线程自己消失,请确保进行清理:
while threads:
threads[-1].join(1) # allow KeyboardInterrup once per second
if not threads[-1].is_alive(): # reap dead Threads
threads.pop()
我的第一个想法是使用thread.join,但这似乎阻塞了主进程(忽略KeyboardInterrupt),直到线程完成。1
多线程Python程序通常会忽略键盘中断生成的SIGINT,尤其是在获取信号的线程正在等待或休眠的情况下。 2
我正在使用Python 2.7,而我的程序在使用时会忽略SIGTERM信号 ThreadPoolExecutor。
经过一些调试后,我发现我的主线程在Thread.join()上被阻塞, 并保持中断,直到呼叫返回。 3
答案 1 :(得分:1)
感谢@MisterMiyagi的建议,我能够测试https://stackoverflow.com/a/3788243/5349916中提到的一些解决方案。
请注意,以下解决方案仅适用于daemon
线程,因为非守护程序将始终阻塞主程序,直到您将join
放在其上完成其工作为止。如果您没有在非守护程序线程上放置join
,那么如果您的主线程退出并且它们是预期的行为,它们将继续在后台运行。
我遇到的问题专门针对daemon
线程。所以这是解决方案。
#1:不要在线程上加入联接,因为这将导致线程阻塞主进程。之所以有效,是因为daemon
线程在主程序退出后立即退出,因此当您不放置join
时,您就不会在主程序中等待,并且{{1}中的time.sleep(1)
}}只是为了确保while
线程继续执行,一旦我按下daemon
,main就会退出,ctrl-c
线程也会退出。
daemon
#2:如果要在线程上放置if __name__ == "__main__":
try:
threads = [threading.Thread(name='daemon', target=daemon)
for _ in range(8)]
for th in threads:
th.daemon = True
th.start()
while True:
time.sleep(1)
# signal.pause() # This worked fine for me on Linux, on Windows it doesn't work, not sure about Mac. I am not recommending this because of platform dependency.
except KeyboardInterrupt:
,请对其使用超时,然后将其保留在join
循环中,直到{{1 }}是while
。这将继续检查thread
列表中的每个线程,直到其存活,然后等待1秒钟执行它。现在,由于alive
的条件将变为threads
,直到while
完成后实际收获为止。它会在1秒的小块时间内阻塞主程序,一旦您按下True
,Thread
就不再存在,因此主程序退出。
ctrl-c
答案 2 :(得分:-1)
这是由于'th.join()'引起的。这使他们基本上互相等待。您是否尝试过使用类似的东西:
except KeyboardInterrupt:
for th in threads:
th._Thread__stop()
sys.exit('....')
这在重现问题时对我有用。希望对您有所帮助! 另外,如果有更多帮助,请继续阅读此线程(无双关!),因为它提供了一些有用的信息: