为什么atexit处理程序不与子进程一起执行,而是操作系统?

2024-06-16 12:48:29 发布

您现在位置:Python中文网/ 问答频道 /正文

https://docs.python.org/3.6/library/subprocess.html#replacing-os-system声明os.system()可以替换为subprocess.call(…, shell=True),但是我注意到用它们调用Python程序时有两个区别:

  1. 对内部程序使用带subprocessCtrl-c时,不会触发atexit

  2. 在外部程序中使用subprocess时,KeyboardInterrupt不可用。

我认为这与如何跨/为子进程处理信号有关,但是使用restore_signals=Truerestore_signals=False没有效果。你知道吗

有没有比手动调用atexit._run_exitfuncs()更好的方法?你知道吗

测试程序:

import atexit
import os
import subprocess
import sys
import time

if int(os.environ.get('RUN_MAIN', 0)):
    atexit.register(lambda: print('atexit inner'))

    print('sub, press Ctrl-C')
    try:
        time.sleep(60)
    except KeyboardInterrupt:
        # atexit._run_exitfuncs()
        print('kbd: inner')

else:
    atexit.register(lambda: print('atexit outer'))

    print('== with os.system')
    try:
        print(os.system('env RUN_MAIN=1 %s t-atexit.py' % sys.executable))
    except KeyboardInterrupt:
        print('kbd: outer1')

    print('== with subprocess.call')
    try:
        subprocess.call(
            ['env', 'RUN_MAIN=1', sys.executable, 't-atexit.py'],
        )
    except KeyboardInterrupt:
        print('kbd: outer2')

    print('== with subprocess.call (shell=True)')
    try:
        subprocess.call(
            'env RUN_MAIN=1 %s t-atexit.py' % sys.executable,
            shell=True,
        )
    except KeyboardInterrupt:
        print('kbd: outer3')

    print('exit outer')

输出:

== with os.system                      
sub, press Ctrl-C
^Ckbd: inner
atexit inner
0
== with subprocess.call
sub, press Ctrl-C
^Ckbd: inner
kbd: outer2
== with subprocess.call (shell=True)
sub, press Ctrl-C
^Ckbd: inner
kbd: outer3
exit outer
atexit outer

我在Django的runserver中注意到了这一点,它在使用(默认)特性重新加载更改的文件时使用子进程(和线程):在这种情况下,安装在子进程中的atexit处理程序(通过pdbrc)不会被执行。你知道吗


Tags: importtrueoswithsysshellcallsystem