Как правильно завершить процесс вместе со всеми его дочерними подпроцессами?

  • 10 сентября 2023 г. 10:17
Ответы на вопрос 2
Для завершения процесса вместе со всеми его дочерними подпроцессами вам следует воспользоваться модулем `psutil`. Вот пример, как можно использовать этот модуль:

```python
import psutil
from subprocess import Popen

def start_stream():
    rtsp_connection = f"ffmpeg -i rtsp://{camera_login}:{camera_pass}@{camera_host}:554/Streaming/channels/1/ -err_detect ignore_err -reorder_queue_size 0 -map 0:v -c:v copy -f rtsp -rtsp_transport tcp rtsp://{rtsp_server}:8554/live.stream"
    p = Popen(rtsp_connection, shell=True, cwd=".")
    p.communicate()

p1 = Popen(['python', '-c', 'start_stream()'], shell=False, cwd=".")
    
# В определенный момент времени
p1.terminate()  # Завершить процесс
parent = psutil.Process(p1.pid)
for child in parent.children(recursive=True):
    child.kill()  # Завершить все дочерние процессы

# Дополнительно можно использовать следующую команду, чтобы дождаться завершения всех процессов:
p1.wait()
```

В приведенном выше коде `p1.terminate()` завершает процесс `p1`, а затем с помощью модуля `psutil` мы завершаем все его дочерние процессы при помощи `child.kill()`. Затем мы можем использовать `p1.wait()` для дожидания окончания выполнения процесса и освобождения ресурсов.

Также, заметьте, что я изменил способ запуска процесса, используя `shell=True`, и передал команду как строку вместо списка аргументов. Это связано с тем, что вам нужно использовать команду `start_stream()` как внешнюю команду для запуска подпроцесса.
Импортируйте модули без скрытого импорта: 

```python
import signal
import subprocess
import sys
```

Избегайте двойной вложенности процессов: 

```python
args = ["ffmpeg", "-i", f"rtsp://{camera_login}:{camera_pass}@{camera_host}:554/Streaming/channels/1/", "-err_detect", "ignore_err", "-reorder_queue_size", "0", "-map", "0:v", "-c:v", "copy", "-f", "rtsp", "-rtsp_transport", "tcp", f"rtsp://{rtsp_server}:8554/live.stream"]
params = {'cwd': '.'}

if sys.platform == 'win32':
    params['creationflags'] = subprocess.CREATE_NEW_PROCESS_GROUP

my_subprocess = Popen(args, **params)

try:
    pass # тут работаешь с процессом
finally:
    my_subprocess.signal(signal.CTRL_C_EVENT)
    
    try:
        my_subprocess.wait(timeout=5.0)
    except subprocess.TimeoutExpired:
        my_subprocess.kill()
```
Похожие вопросы