Задать вопрос
@valerr007

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

как завершить процесс и дочерние подпроцессы, освободив ресурсы ?

Есть такая функция:

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, cwd=".")
    p.wait()




p1 = Process(target=start_stream, name="rtsp_stream")
p1.start()


Я хочу в определённый момент завершить процесс и запущенную через Popen команду. Но процесс не завершается ((

Пробовал через p1.kill() - но это не работает.
  • Вопрос задан
  • 430 просмотров
Подписаться 1 Простой Комментировать
Решения вопроса 1
Vindicar
@Vindicar
RTFM!
В-нулевых, не прячь импорты, не всегда понятно что откуда берётся.
Во-первых, зачем тебе два уровня вложенности в процессах? Сначала делаешь дочерний процесс через multiprocessing.Process, а потом в нём запускаешь еще один процесс через Popen. Смысл? Собственно, результат предсказуем - ты жестко прибиваешь (kill()) первый дочерний процесс, и он не успевает ничего сделать со вторым.
Во-вторых, Popen уже имеет полезные методы типа terminate(). Но тут есть тонкость - под линуксом этот метод посылает сигнал SIGTERM, на который процесс может отреагировать и спокойно завершить свою работу. Под виндой используется функция WinAPI TerminateProcess(), которая жёстко прибивает процесс, не давая ему шанса завершить работу. Будет практичнее использовать метод signal() в сочетании с константой signal.CTRL_C_EVENT - это будет эквивалентом нажатия Ctrl-C (или Ctrl-Break) в консоли дочернего процесса. Большинство процессов реагируют на это завершением работы. Но под виндой надо будет указать дополнительный параметр для Popen(), чтобы это сработало.

Так что я бы попробовал что-то в таком духе:
import signal
import subprocess
import sys

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.DETACHED_PROCESS |  # если хочешь, чтобы ffmpeg запускался тихо и не спамил в твой stdout
        # subprocess.CREATE_NEW_CONSOLE |  # если хочешь, чтобы открывалась новая консоль для ffmpeg
        subprocess.CREATE_NEW_PROCESS_GROUP  # по докам, это требуется для нормальной работы ctrl-c
    )
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()  # тогда прибиваем
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы