Python 中如何处理信号和键盘中断?
How are signals and KeyboardInterrupt handled in Python?
我有两个 Python 脚本 foo.py
和 bar.py
,foo.py
将通过 os.system()
调用 bar.py
。
#foo.py
import os
print os.getpid()
os.system("python dir/bar.py")
#bar.py
import time
time.sleep(10)
print "over"
假设foo.py
的pid是123,如果程序正常终止,会打印
123
over
如果我在 运行 时键入 kill 123
,我将得到以下输出
123
Terminated
over
如果我在 运行 时按 Ctrl-C,我会得到类似
的结果
123
^CTraceback (most recent call last):
File "dir/bar.py", line 4, in <module>
time.sleep(10)
KeyboardInterrupt
但是如果我在 运行 时键入 kill -SIGINT 123
,程序似乎会忽略该信号并正常退出。
123
over
在我看来,
如果我输入 kill 123
,子流程将不会受到影响。
如果我键入 Ctrl-C,两个进程都将终止。
如果我输入 kill -SIGINT 123
而子进程是 运行,信号将被忽略。
有人可以向我解释一下它是如何工作的吗?
Ctrl-C 和 kill -SIGINT
不应该是等价的吗?
如果我输入kill 123
是不是保证子进程不受影响(如果恰好是运行)?
顺便说一句,我在Ubuntu 14.04。谢谢!
让我们依次考虑每种情况:
if I type kill 123
, the sub-process will not be affected.
是的,这就是 kill [pid]
的工作原理。它只向您要终止的进程发送信号。如果要将信号发送给一组进程,则必须使用代表 process group.
的负数
if I type Ctrl-C, both processes will be terminated.
我假设你的意思是 "terminated by Ctrl-C"。实际上,情况并非如此:只有 child 被终止。如果您在 foo.py
的末尾添加这样一行 print "I'm a little teapot"
,您将看到该行被打印出来。发生的事情是 child 收到信号。 parent 然后从 os.system
继续。如果没有附加行,它 看起来 就像 parent 也受到 Ctrl-C 的影响,但事实并非如此,如附加行所示。
您 shell 确实将信号发送到与 tty 关联的进程组,其中 包括 parent。 但是,os.system
使用system
调用,它会在进行调用的进程中阻止SIGINT
和SIGQUIT
信号。所以parent是免疫的。
如果您不使用os.system
,那么您的进程将受到SIGINT
的影响。为 foo.py
:
尝试此代码
import os
import subprocess
print os.getpid()
p = subprocess.Popen(["python", "dir/bar.py"])
p.wait()
print "I'm a little teapot"
如果您在运行时点击 Ctrl-C,您将得到两个回溯:一个来自 parent,一个来自 child:
$ python foo.py
29626
^CTraceback (most recent call last):
File "dir/bar.py", line 4, in <module>
Traceback (most recent call last):
File "foo.py", line 8, in <module>
time.sleep(10)
KeyboardInterrupt p.wait()
File "/usr/lib/python2.7/subprocess.py", line 1389, in wait
pid, sts = _eintr_retry_call(os.waitpid, self.pid, 0)
File "/usr/lib/python2.7/subprocess.py", line 476, in _eintr_retry_call
return func(*args)
KeyboardInterrupt
if I type kill -SIGINT 123
while the sub-process is running, the signal will be ignored.
见上文。
Isn't Ctrl-C and kill -SIGINT
supposed to be equivalent?
Ctrl-C 确实发送 SIGINT
到与您在其中发出 Ctrl-C.
的 tty 关联的前台进程组
If I type kill 123
is it guaranteed that the sub-process will not be affected (if it happens to be running)?
它自己 kill 123
只会将信号发送给 pid
123 的进程。Children 不会受到影响。
我有两个 Python 脚本 foo.py
和 bar.py
,foo.py
将通过 os.system()
调用 bar.py
。
#foo.py
import os
print os.getpid()
os.system("python dir/bar.py")
#bar.py
import time
time.sleep(10)
print "over"
假设foo.py
的pid是123,如果程序正常终止,会打印
123
over
如果我在 运行 时键入 kill 123
,我将得到以下输出
123
Terminated
over
如果我在 运行 时按 Ctrl-C,我会得到类似
的结果123
^CTraceback (most recent call last):
File "dir/bar.py", line 4, in <module>
time.sleep(10)
KeyboardInterrupt
但是如果我在 运行 时键入 kill -SIGINT 123
,程序似乎会忽略该信号并正常退出。
123
over
在我看来,
如果我输入 kill 123
,子流程将不会受到影响。
如果我键入 Ctrl-C,两个进程都将终止。
如果我输入 kill -SIGINT 123
而子进程是 运行,信号将被忽略。
有人可以向我解释一下它是如何工作的吗?
Ctrl-C 和 kill -SIGINT
不应该是等价的吗?
如果我输入kill 123
是不是保证子进程不受影响(如果恰好是运行)?
顺便说一句,我在Ubuntu 14.04。谢谢!
让我们依次考虑每种情况:
if I type
kill 123
, the sub-process will not be affected.
是的,这就是 kill [pid]
的工作原理。它只向您要终止的进程发送信号。如果要将信号发送给一组进程,则必须使用代表 process group.
if I type Ctrl-C, both processes will be terminated.
我假设你的意思是 "terminated by Ctrl-C"。实际上,情况并非如此:只有 child 被终止。如果您在 foo.py
的末尾添加这样一行 print "I'm a little teapot"
,您将看到该行被打印出来。发生的事情是 child 收到信号。 parent 然后从 os.system
继续。如果没有附加行,它 看起来 就像 parent 也受到 Ctrl-C 的影响,但事实并非如此,如附加行所示。
您 shell 确实将信号发送到与 tty 关联的进程组,其中 包括 parent。 但是,os.system
使用system
调用,它会在进行调用的进程中阻止SIGINT
和SIGQUIT
信号。所以parent是免疫的。
如果您不使用os.system
,那么您的进程将受到SIGINT
的影响。为 foo.py
:
import os
import subprocess
print os.getpid()
p = subprocess.Popen(["python", "dir/bar.py"])
p.wait()
print "I'm a little teapot"
如果您在运行时点击 Ctrl-C,您将得到两个回溯:一个来自 parent,一个来自 child:
$ python foo.py
29626
^CTraceback (most recent call last):
File "dir/bar.py", line 4, in <module>
Traceback (most recent call last):
File "foo.py", line 8, in <module>
time.sleep(10)
KeyboardInterrupt p.wait()
File "/usr/lib/python2.7/subprocess.py", line 1389, in wait
pid, sts = _eintr_retry_call(os.waitpid, self.pid, 0)
File "/usr/lib/python2.7/subprocess.py", line 476, in _eintr_retry_call
return func(*args)
KeyboardInterrupt
if I type
kill -SIGINT 123
while the sub-process is running, the signal will be ignored.
见上文。
Isn't Ctrl-C and
kill -SIGINT
supposed to be equivalent?
Ctrl-C 确实发送 SIGINT
到与您在其中发出 Ctrl-C.
If I type
kill 123
is it guaranteed that the sub-process will not be affected (if it happens to be running)?
它自己 kill 123
只会将信号发送给 pid
123 的进程。Children 不会受到影响。