Python Subprocess Popen으로 시작된 프로세스를 죽일 때 Stdout-pipe를 어떻게 닫으려면?

StackOverflow https://stackoverflow.com/questions/1624254

문제

다른 스레드에서 시작된 하위 프로세스를 죽일 때 통신 파이프를 종료 할 수 있는지 궁금합니다. 내가 COLLIC ()을 호출하지 않으면 kill ()은 예상대로 작동하여 5 개가 아닌 1 초 후에 프로세스를 종료합니다.

비슷한 문제에 대한 토론을 찾았습니다 여기, 그러나 나는 진짜 답변을 얻지 못했습니다. 나는 파이프를 닫거나 하위 사기업 (예에서 "수면")을 명시 적으로 죽이고 파이프를 차단 해제하기 위해 죽일 수 있어야한다고 가정합니다.

나는 또한 그녀에게 답을 찾으려고 노력했지만 이것 그리고 이것 그리고 이것, 내가 말할 수있는 한이 문제를 직접 해결하지 못한다 (?).

따라서 내가하고 싶은 것은 두 번째 스레드에서 명령을 실행하고 모든 출력을 얻을 수 있지만 원하는 경우 즉시 죽일 수 있다는 것입니다. 파일과 꼬리를 통해 갈 수는 있지만 더 나은 방법이 있어야한다고 생각합니까?

import subprocess, time
from threading import Thread

process = None

def executeCommand(command, runCommand):
    Thread(target=runCommand, args=(command,)).start()

def runCommand(command):
    global process
    args = command.strip().split()
    process = subprocess.Popen(args, shell=False, stdout=subprocess.PIPE)

    for line in process.communicate():
        if line:
            print "process:", line,

if __name__ == '__main__':
    executeCommand("./ascript.sh", runCommand)
    time.sleep(1)
    process.kill()

이것은 스크립트입니다.

#!/bin/bash
echo "sleeping five"
sleep 5
echo "slept five"

산출

$ time python poc.py 
process: sleeping five

real    0m5.053s
user    0m0.044s
sys 0m0.000s
도움이 되었습니까?

해결책

문제는 Process.kill ()가 Bash 스크립트의 하위 프로세스가 아니라 즉각적인 아동 프로세스 (BASH) 만 죽인다라고 생각합니다.

문제와 해결책은 여기에 설명되어 있습니다.

Popen (..., preexec_fn = os.setsid)을 사용하여 프로세스 그룹을 만들고 os.pgkill 전체 프로세스 그룹을 죽입니다. 예를 들어

import os
import signal
import subprocess
import time
from threading import Thread

process = None

def executeCommand(command, runCommand):
    Thread(target=runCommand, args=(command,)).start()

def runCommand(command):
    global process
    args = command.strip().split()
    process = subprocess.Popen(
        args, shell=False, stdout=subprocess.PIPE, preexec_fn=os.setsid)

    for line in process.communicate():
        if line:
            print "process:", line,

if __name__ == '__main__':
    executeCommand("./ascript.sh", runCommand)
    time.sleep(1)
    os.killpg(process.pid, signal.SIGKILL)

$ time python poc.py 
process: sleeping five

real    0m1.051s
user    0m0.032s
sys 0m0.020s

다른 팁

이 작업을 수행하는 가장 쉬운 방법은 메인 스레드에서 킬 깃발을 설정하고 커뮤니케이션 직전에 스크립트 실행 스레드에서 깃발을 확인하여 깃발이있을 때 스크립트를 죽이는 것입니다. True.

Python의 슈퍼 거친 동시성의 희생자 인 것 같습니다. 스크립트를 이것으로 변경하십시오.

#!/bin/bash
echo "sleeping five"
sleep 5
echo "sleeping five again"
sleep 5
echo "slept five"

그런 다음 출력이됩니다.

process: sleeping five

real    0m5.134s
user    0m0.000s
sys     0m0.010s

전체 스크립트가 실행되면 시간은 10 초입니다. 따라서 Bash 스크립트가 잠들 때까지 Python Control 스레드가 실제로 실행되지 않는 것처럼 보입니다. 마찬가지로 스크립트를 변경하면 다음과 같습니다.

#!/bin/bash
echo "sleeping five"
sleep 1
sleep 1
sleep 1
sleep 1
sleep 1
echo "slept five"

그런 다음 출력이됩니다.

process: sleeping five

real    0m1.150s
user    0m0.010s
sys     0m0.020s

요컨대, 코드는 논리적으로 구현 된대로 작동합니다. :)

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top