2009-10-26 16 views
9

मुझे आश्चर्य है कि एक अलग थ्रेड में एक उपप्रोसेस शुरू होने पर संचार पाइप को बंद करना संभव है। अगर मैं संवाद() को कॉल नहीं करता हूं तो मार डालें() उम्मीद के अनुसार काम करेगा, प्रक्रिया को पांच की बजाय एक सेकंड के बाद समाप्त कर देगा।पायथन उपप्रोसेन पॉपन के साथ शुरू की गई प्रक्रिया को मारते समय मैं स्टडआउट-पाइप को कैसे बंद करूं?

मुझे इसी तरह की समस्या here की चर्चा मिली, लेकिन मुझे कोई वास्तविक जवाब नहीं मिला। मुझे लगता है कि मुझे या तो पाइप को बंद करने या उप-उपप्रकार (जिसे उदाहरण में "नींद" है) को स्पष्ट रूप से मारने में सक्षम होना चाहिए और पाइप को अनवरोधित करने के लिए उसे मारना है।

मैं भी इतने पर जवाब उसे ढूँढने की कोशिश की, लेकिन मैं केवल this और this और this, जो सीधे जहाँ तक मैं बता सकता है इस समस्या का समाधान नहीं करते हैं (?)।

तो मैं जो चीज करना चाहता हूं वह दूसरे थ्रेड में कमांड चलाने में सक्षम होना है और इसके सभी आउटपुट प्राप्त करना है, लेकिन जब मैं चाहूं तो इसे तुरंत मारने में सक्षम हूं। मैं एक फ़ाइल और पूंछ के माध्यम से या इसी तरह के माध्यम से जा सकता था, लेकिन मुझे लगता है कि ऐसा करने के लिए एक बेहतर तरीका होना चाहिए?

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 
+0

जब 'process.kill()' कहा जाता है, '।/ascript.sh' मर जाता है लेकिन' नींद 5' इसके अंदर नहीं करता है। दिलचस्प है, हालांकि, पाइथन तुरंत '/ ascript.sh' मरने के बाद वापस नहीं आता है। –

उत्तर

6

मुझे लगता है कि समस्या यह है कि प्रक्रिया.किल() केवल तत्काल बाल प्रक्रिया (बैश) को मार देती है, न कि बैश स्क्रिप्ट की उप-प्रक्रियाओं को।

समस्या और समाधान का वर्णन यहां:

popen उपयोग करें (..., preexec_fn = os.setsid) एक प्रक्रिया समूह और ओएस बनाने के लिए। पूरे प्रक्रिया समूह को मारने के लिए 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 
-1

ऐसा लगता है कि अजगर के सुपर मोटे कणों का संगामिति का शिकार हो सकता है की तरह। यह करने के लिए अपनी स्क्रिप्ट बदलें:

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

संक्षेप में, अपने कोड के रूप में तार्किक कार्यान्वित काम करता है। :)

+0

उदाहरण में नींद स्क्रिप्ट में किसी भी लंबे ऑपरेशन के लिए केवल प्लेसहोल्डर है। सवाल यह है कि, मैं पाइप को बंद करने के लिए कैसे प्राप्त करूं ताकि कोड संचार() पर लटका न सके? वैकल्पिक रूप से, मैं ब्लॉक को रिहा करने के लिए किस "सब-सबप्रोसेसेस" को मारने के लिए कैसे पता लगा सकता हूं? – icecream

+0

क्या आपका मतलब है कि यह ग्लोबल इंटरप्रेटर लॉक काम पर कड़ी मेहनत है? http://docs.python.org/c-api/init.html#thread-state-and-the-global-interpreter-lock –

+0

हो सकता है? कोई सुझाव? – icecream

0

ऐसा लगता है कि ऐसा करने का सबसे आसान तरीका और बहुप्रवाह समस्याओं को दूर करना मुख्य धागे से एक हत्या ध्वज सेट करना होगा, और संचार, हत्या से ठीक पहले स्क्रिप्ट-थ्रेड थ्रेड में इसकी जांच करना होगा स्क्रिप्ट जब ध्वज True है।

+0

असल में, यह बहुसंख्यक समस्या से पाइप को अवरुद्ध करने में एक समस्या है। मुझे एक अलग थ्रेड चाहिए ताकि मैं इसे कहीं से बंद कर सकूं। अगर मैं खोल से "मार" करता हूं, तो यह स्क्रिप्ट और इसके उपप्रवाहों को मार देता है। पाइथन की हत्या ऐसा करने में विफल रही क्योंकि ऐसा लगता है कि पाइप बंद हो जाए। – icecream