كيف أقوم بإغلاق أنبوب stdout عند قتل عملية بدأت باستخدام عملية python الفرعية Popen؟

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

سؤال

أتساءل عما إذا كان من الممكن إيقاف تشغيل أنبوب الاتصال عند بدء عملية فرعية في سلسلة رسائل مختلفة.إذا لم أتصل بـ communication()، فستعمل kill() كما هو متوقع، وتنهي العملية بعد ثانية واحدة بدلاً من خمس.

لقد وجدت مناقشة لمشكلة مماثلة هنا, ، لكن لم أحصل على إجابات حقيقية.أفترض أنه يجب علي إما أن أكون قادرًا على إغلاق الأنبوب أو إيقاف العملية الفرعية بشكل صريح (وهي "النوم" في المثال) وقتل ذلك لإلغاء قفل الأنبوب.

لقد حاولت أيضًا العثور على الإجابة عليها على SO، لكنني وجدت فقط هذا و هذا و هذا, ، والتي لا تعالج هذه المشكلة بشكل مباشر بقدر ما أستطيع أن أقول (؟).

لذا فإن الشيء الذي أريد القيام به هو أن أكون قادرًا على تشغيل أمر في سلسلة رسائل ثانية والحصول على كل مخرجاته، ولكن أكون قادرًا على إيقافه على الفور عندما أرغب في ذلك.يمكنني المرور عبر ملف وتتبعه أو ما شابه، ولكن أعتقد أنه يجب أن تكون هناك طريقة أفضل للقيام بذلك؟

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.

ويبدو أنك قد تكون ضحية للسوبر الخشنة التزامن بايثون الحبيبات. تغيير السيناريو الخاص بك إلى هذا:

#!/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

إذا ركض النصي بأكمله، سوف يكون الوقت 10S. لذلك يبدو وكأنه لا يعمل موضوع السيطرة الثعبان في الواقع حتى بعد ينام النصي باش. وبالمثل، إذا قمت بتغيير السيناريو الخاص بك إلى هذا:

#!/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