从 Node 杀死 Python 进程不会杀死 Python 的子进程(子进程是 ffmpeg.exe)

Killing a Python process from Node doesn't kill Python's child process (child process being ffmpeg.exe)

我正在开发 Electron 应用程序。在这个应用程序中,我生成了一个 Python 进程,文件路径作为参数,然后文件本身被传递给 ffmpeg(通过 ffmpeg-python 模块),然后通过一些 Tensorflow 函数.

我正在尝试处理用户在整个后台进程进行时关闭 Electron 应用程序的情况。不过,从我的测试来看,ffmpeg 的进程似乎无论如何都会保持运行。我在 Windows 上,正在查看任务管理器,但我不确定发生了什么:关闭 Electron 应用程序时 window,有时 ffmpeg.exe 将是一个进程,有时它会留在电子进程组中。

我注意到如果我通过关闭 window 来终止 Electron 的进程,一旦 ffmpeg 完成它的工作,python 进程也会关闭,所以我猜这是半工作。问题是,ffmpeg 正在做大量的事情,如果用户需要关闭 window,那么 ffmpeg 进程也需要被杀死。但我无法以任何方式实现。

我已经尝试了一些东西,所以我会粘贴一些代码:

main.js

// retrieve video data
ipcMain.handle('get-games', async (event, arg) => {
    const spawn = require('child_process').spawn;
    const pythonProcess = spawn('python', ["./backend/predict_games.py", arg]);

    // sets pythonProcess as a global variable to be accessed when quitting the app
    global.childProcess = pythonProcess;

    return new Promise((resolve, reject) => {
        let result = "";

        pythonProcess.stdout.on('data', async (data) => {
            data = String(data);

            if (data.startsWith("{"))
                result = JSON.parse(data);
        });

        pythonProcess.on('close', () => {
            resolve(result);
        })

        pythonProcess.on('error', (err) => {
            reject(err);
        });
    })
});

app.on('before-quit', function () {
    global.childProcess.kill('SIGINT');
});

predict_games.py(ffmpeg部分)

def convert_video_to_frames(fps, input_file):
    # a few useful directories
    local_dir = os.path.dirname(os.path.abspath(__file__))
    snapshots_dir = fr"{local_dir}/snapshots/{input_file.stem}"

    # creates snapshots folder if it doesn't exist
    Path(snapshots_dir).mkdir(parents=True, exist_ok=True)

print(f"Processing: {Path(fr'{input_file}')}")
try:
    (
        ffmpeg.input(Path(input_file))
        .filter("fps", fps=fps)
        .output(f"{snapshots_dir}/%d.jpg", s="426x240", start_number=0)
        .run(capture_stdout=True, capture_stderr=True)
    )
except ffmpeg.Error as e:
    print("stdout:", e.stdout.decode("utf8"))
    print("stderr:", e.stderr.decode("utf8"))

有人知道吗?

好吧,我终于能够解决这个问题了!由于 ffmpeg-python 只是好旧的 ffmpeg 的绑定集合,可执行文件本身仍然是模块的核心。这也意味着当ffmpeg为运行时,出现类似这样的画面:

... 

    Metadata:
      handler_name    : VideoHandler
      vendor_id       : [0][0][0][0]
  Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 159 kb/s (default)
    Metadata:
      handler_name    : SoundHandler
      vendor_id       : [0][0][0][0]
Stream mapping:
  Stream #0:0 (h264) -> fps:default
  fps:default -> Stream #0:0 (mjpeg)

...

Press [q] to stop, [?] for help

是幕后发生的事情。一旦意识到这一点,我所要做的就是找到一种方法将 'q' 发送到 ffmpeg 的标准输入。我通过在 window-all-closed 事件中添加此片段来做到这一点:

app.on('window-all-closed', () => {
    // writes a 'q' in ffmpeg's terminal to quit ffmpeg's process
    // reminder: python gets closed when the Electron app is closed
    global.childProcess.stdin.write("q\n");

    if (process.platform !== 'darwin') app.quit()
})

与问题中的片段相比,Python 脚本本身没有受到影响,这是我最终修改的唯一内容。现在每次我退出我的 Electron 应用程序时,ffmpeg 都会收到 'q'。 Python 进程不需要手动终止,因为 Electron 已经为您完成了。

所以问题解决了。 :)