2009-10-09 16 views
5

मुझे पाइथन की उपप्रोसेस.पोपेन विधि में कोई समस्या है।सबप्रोसेस क्यों है। बच्चे की प्रक्रिया समाप्त होने तक प्रतीक्षा न करें?

यहां एक टेस्ट स्क्रिप्ट है जो समस्या का प्रदर्शन करती है। यह एक लिनक्स बॉक्स पर चल रहा है।

#!/usr/bin/env python 
import subprocess 
import time 

def run(cmd): 
    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) 
    return p 

### START MAIN 
# copy some rows from a source table to a destination table 
# note that the destination table is empty when this script is run 
cmd = 'mysql -u ve --skip-column-names --batch --execute="insert into destination (select * from source limit 100000)" test' 
run(cmd) 

# check to see how many rows exist in the destination table 
cmd = 'mysql -u ve --skip-column-names --batch --execute="select count(*) from destination" test' 
process = run(cmd) 
count = (int(process.communicate()[0][:-1])) 

# if subprocess.Popen() waited for the child to terminate than count should be 
# greater than 0 
if count > 0: 
    print "success: " + str(count) 
else: 
    print "failure: " + str(count) 
    time.sleep(5) 

    # find out how many rows exists in the destination table after sleeping 
    process = run(cmd) 
    count = (int(process.communicate()[0][:-1])) 
    print "after sleeping the count is " + str(count) 

आम तौर पर इस स्क्रिप्ट से उत्पादन होता है:

success: 100000 

लेकिन कभी कभी यह है

failure: 0 
after sleeping the count is 100000 

ध्यान दें कि विफलता के मामले में, चुनें तुरंत डालने के बाद 0 पंक्तियों लेकिन उसके बाद से पता चलता 5 सेकंड के लिए सोते हुए दूसरा चयन सही ढंग से 100000 की पंक्ति गणना दिखाता है। मेरा निष्कर्ष यह है कि निम्न में से एक सत्य है:

  1. subprocess.Popen समाप्त करने के लिए बच्चे को थ्रेड के लिए प्रतीक्षा नहीं है - यह प्रलेखन खंडन करने के लिए लगता है
  2. mysql डालने परमाणु नहीं है - mysql की मेरी समझ से संकेत मिलता है डालने परमाणु है
  3. का चयन नहीं है लगता है सही पंक्ति अभी गिनती देखकर - एक दोस्त है जो mysql बेहतर जानता है की तुलना में मैं यह या तो

मैं क्या याद आ रही है ऐसा नहीं होना चाहिए करने के लिए अनुसार?

एफवाईआई, मुझे पता है कि यह पाइथन से MySQL के साथ बातचीत करने का एक हैकी तरीका है और MySQLdb की संभावना नहीं है, लेकिन मुझे उत्सुकता है कि यह विधि क्यों काम नहीं करती है।

+0

सभी को धन्यवाद। सबप्रोसेस दस्तावेज को फिर से देखकर मैं देखता हूं कि मुझे "आदेश के लिए प्रतीक्षा करें" टिप्पणी से फेंक दिया गया था जो सुविधा विधियों अनुभागों में दिखाई देता है जो पॉपन विधि अनुभाग नहीं है। मैंने जेड के जवाब को मंजूरी दे दी क्योंकि यह मेरे मूल प्रश्न का सबसे अच्छा जवाब देता है, हालांकि मुझे लगता है कि मैं अपनी भविष्य की स्क्रिप्टिंग आवश्यकताओं के लिए पॉल के समाधान का उपयोग करूंगा। –

+0

ध्यान रखें कि os.system (जब तक आप इसके साथ कुछ और नहीं करते) प्रक्रिया के रिटर्न VALUE (आमतौर पर 0 या 1) देता है। आपको या तो काटने मत देना। –

उत्तर

20

subprocess.Popen, तत्काल, प्रोग्राम चलाता है। हालांकि, यह इसके लिए इंतजार नहीं करता है - यह पृष्ठभूमि में इसे बंद कर देता है जैसे कि आप एक शेल में cmd & टाइप करेंगे। तो, उपरोक्त कोड में, आपने अनिवार्य रूप से रेस हालत को परिभाषित किया है - यदि समय में आवेषण खत्म हो सकते हैं, तो यह सामान्य दिखाई देगा, लेकिन यदि आपको अप्रत्याशित आउटपुट नहीं मिलता है। आप अपने पहले run() 'डी पीआईडी ​​को समाप्त करने के लिए इंतजार नहीं कर रहे हैं, आप बस इसके Popen इंस्टेंस को जारी कर रहे हैं और जारी रखते हैं।

मुझे यकीन है कि यह कैसे व्यवहार प्रलेखन के विपरीत है नहीं कर रहा हूँ क्योंकि है कि इंगित करने के लिए यह की तरह है, के लिए इंतजार कर रहे थे नहीं है प्रतीत popen पर कुछ बहुत स्पष्ट तरीके:

Popen.wait() 
    Wait for child process to terminate. Set and return returncode attribute. 

मैं सहमत हैं, हालांकि, कि इस मॉड्यूल के लिए प्रलेखन में सुधार किया जा सकता है।

कार्यक्रम के लिए प्रतीक्षा करने के लिए समाप्त करने के लिए, मैं subprocess की सुविधा विधि, subprocess.call का उपयोग कर, या एक Popen वस्तु पर communicate का उपयोग कर (मामले के लिए जब आप stdout जरूरत है) की सलाह देते हैं। आप पहले से ही अपने दूसरे कॉल के लिए यह कर रहे हैं।

### START MAIN 
# copy some rows from a source table to a destination table 
# note that the destination table is empty when this script is run 
cmd = 'mysql -u ve --skip-column-names --batch --execute="insert into destination (select * from source limit 100000)" test' 
subprocess.call(cmd) 

# check to see how many rows exist in the destination table 
cmd = 'mysql -u ve --skip-column-names --batch --execute="select count(*) from destination" test' 
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) 
try: count = (int(process.communicate()[0][:-1])) 
except: count = 0 

इसके अतिरिक्त, ज्यादातर मामलों में, आपको शेल में कमांड चलाने की आवश्यकता नहीं है। यह उन मामलों में से एक है, लेकिन आपको अनुक्रम की तरह अपने आदेश को फिर से लिखना होगा।

prog = ["mysql", "-u", "ve", "--execute", 'insert into foo values ("snargle", 2)'] 
subprocess.call(prog) 

यह भी काम करेंगे, और इंजेक्षन नहीं होगा जैसा कि आप उम्मीद थी: यह कर कि जिस तरह से भी आप पारंपरिक खोल इंजेक्शन से बचने और के हवाले बारे में कम चिंता है, तो तरह की अनुमति देता है

prog = ["printf", "%s", "<", "/etc/passwd"] 
subprocess.call(prog) 

इसे अंतःक्रिया से आजमाएं। आप खोल इंजेक्शन की संभावनाओं से बचते हैं, खासकर यदि आप उपयोगकर्ता इनपुट स्वीकार कर रहे हैं। ^)

+1

मैं subprocess.call का उपयोग कर रहा हूं और यह भी प्रतीक्षा नहीं कर रहा है। बाद में बयान कोड को उस फ़ाइल को हटाने के लिए कहता है जो अभी चल रहा है, और कोड को चलाने से पहले इसे कॉल किया जा रहा है, प्रोग्राम को दुर्घटनाग्रस्त कर रहा है। – Elliot

4

Dude, क्यों आपको लगता था कि subprocess.Popen एक wait विधि के साथ एक वस्तु लौट आए, जब तक कि यह: मैं आप उपप्रक्रिया साथ संवाद स्थापित करने, क्योंकि आप काम करने के लिए दृश्यों हो रही परेशानी में भाग के कम-भयानक स्ट्रिंग विधि का उपयोग कर रहे संदेह था, क्योंकि इंतज़ार कर रहा था नहीं, अंतर्निहित आंतरिक, तत्काल, और अपरिहार्य, आप अनुमान दिखाई देते हैं के रूप में ...?! सबसे आम कारण एक उपप्रक्रिया अंडे देने के लिए नहीं है, यह खत्म करने के लिए के लिए तुरंत प्रतीक्षा करने के लिए, बल्कि यह आगे बढ़ना (एक और कोर पर जैसे जाने के लिए, या कम से सबसे बुरा समय टुकड़ा करने की क्रिया द्वारा - कि ऑपरेटिंग सिस्टम के है - और हार्डवेयर के - तलाश) एक ही समय में माता-पिता की प्रक्रिया जारी है; जब माता-पिता की प्रक्रिया के लिए उपप्रक्रिया अनुरूप तैयार किया जाए प्रतीक्षा करने के लिए की जरूरत है, यह स्पष्ट रूप से वस्तु मूल subprocess.Process कॉल द्वारा दिया पर wait कॉल करेंगे।

7

आप पूरी तरह उपप्रक्रिया का उपयोग करें और popen करने की जरूरत नहीं है, यह आम तौर पर os.system उपयोग करने के लिए आसान है।

import os 
run = os.system #convenience alias 
result = run('mysql -u ve --execute="select * from wherever" test') 

popen के विपरीत, os.system अपनी प्रक्रिया के लिए अपनी स्क्रिप्ट के अगले चरण पर जाने से पहले वापस जाने के लिए इंतजार करता है: उदाहरण के लिए, त्वरित स्क्रिप्ट के लिए मैं अक्सर कुछ इस तरह से करते हैं। डॉक्स में उस पर

और जानकारी: महान जवाब के लिए http://docs.python.org/library/os.html#os.system

संबंधित मुद्दे