2010-10-21 7 views
9

का उपयोग करके बहुत बड़ा इनपुट और पाइपिंग मुझे बहुत सरल समस्या है। मेरे पास एक बड़ी फाइल है जो तीन चरणों से गुज़रती है, एक बाहरी प्रोग्राम का उपयोग करके एक डिकोडिंग चरण, पाइथन में कुछ प्रोसेसिंग, और फिर किसी अन्य बाहरी प्रोग्राम का उपयोग करके रिकोडिंग। मैं यूनिक्स पाइप बनाने के बजाय पायथन में ऐसा करने की कोशिश करने के लिए subprocess.Popen() का उपयोग कर रहा हूं। हालांकि, सभी डेटा स्मृति में buffered हैं। क्या इस कार्य को करने का कोई पागल तरीका है, या क्या मैं एक साधारण पायथन लिपि पर वापस आ रहा हूं जो स्टडीन से पढ़ता है और किसी भी तरफ यूनिक्स पाइप के साथ stdout लिखता है?subprocess.Popen

import os, sys, subprocess 

def main(infile,reflist): 
    print infile,reflist 
    samtoolsin = subprocess.Popen(["samtools","view",infile], 
            stdout=subprocess.PIPE,bufsize=1) 
    samtoolsout = subprocess.Popen(["samtools","import",reflist,"-", 
            infile+".tmp"],stdin=subprocess.PIPE,bufsize=1) 
    for line in samtoolsin.stdout.read(): 
     if(line.startswith("@")): 
      samtoolsout.stdin.write(line) 
     else: 
      linesplit = line.split("\t") 
      if(linesplit[10]=="*"): 
       linesplit[9]="*" 
      samtoolsout.stdin.write("\t".join(linesplit)) 
+0

* एक बड़ी फ़ाइल * क्या है? – eumiro

+1

अच्छा सवाल। उपलब्ध रैम से बड़ा। – seandavi

+0

मेरे हिस्से पर बेवकूफ त्रुटि। मैंने उपरोक्त लूप में पढ़ने() विधि का उपयोग किया। सही पंक्ति को निश्चित रूप से .read() नहीं होना चाहिए क्योंकि samtools.stdout वास्तव में एक फ़ाइल जैसी वस्तु है। – seandavi

उत्तर

4

इस छोटे बदलाव को करने का प्रयास करें, देखें कि दक्षता बेहतर है या नहीं।

for line in samtoolsin.stdout: 
     if(line.startswith("@")): 
      samtoolsout.stdin.write(line) 
     else: 
      linesplit = line.split("\t") 
      if(linesplit[10]=="*"): 
       linesplit[9]="*" 
      samtoolsout.stdin.write("\t".join(linesplit)) 
+0

वह मुद्दा था, Anijhaw। ध्यान देने के लिए धन्यवाद। – seandavi

5

popen एक bufsize पैरामीटर है कि स्मृति में बफर के आकार को सीमित होगा। यदि आप स्मृति में फ़ाइलों को बिल्कुल नहीं चाहते हैं, तो आप फ़ाइल ऑब्जेक्ट को stdin और stdout पैरामीटर के रूप में पास कर सकते हैं। subprocess docs से:

bufsize, अगर दिया, निर्मित खुला() फ़ंक्शन करने के लिए इसी तर्क के रूप में एक ही अर्थ है: 0 unbuffered मतलब है, इसका मतलब है 1 बफ़र लाइन, किसी भी अन्य सकारात्मक मूल्य एक बफर का उपयोग का मतलब है उस आकार के लगभग (लगभग)। एक नकारात्मक bufsize का मतलब सिस्टम डिफ़ॉल्ट का उपयोग करना है, जिसका आमतौर पर पूरी तरह से buffered का मतलब है। Bufsize के लिए डिफ़ॉल्ट मान 0 (unbuffered) है।

+0

सीधे 'संवाद' विधि के तहत, उसी दस्तावेज़ से: "नोट डेटा पढ़ने में स्मृति में buffered है, इसलिए डेटा आकार बड़ा या असीमित है, तो इस विधि का उपयोग न करें।" –

+0

मैंने उपरोक्त कोड पोस्ट किया है। यह कोड निश्चित रूप से स्मृति उपयोग के संदर्भ में स्ट्रेटोस्फीयर की ओर बढ़ने वाली पायथन प्रक्रिया की ओर जाता है, इसलिए मुझे निश्चित रूप से कुछ विवरण याद आ रहा है .... – seandavi

+0

दस्तावेज़ों से: संस्करण 3.3.1 में बदला गया: bufsize अब डिफ़ॉल्ट पर -1 को बफरिंग सक्षम करने के लिए उस व्यवहार से मेल खाने के लिए डिफ़ॉल्ट जो अधिकांश कोड अपेक्षा करता है। – cmcginty

1

हालांकि, सभी डेटा स्मृति में बफ़र कर रहे हैं ...

आप subprocess.Popen.communicate() का उपयोग कर रहे हैं? डिज़ाइन द्वारा, यह फ़ंक्शन प्रक्रिया समाप्त होने की प्रतीक्षा करेगा, बफर में डेटा जमा करने के दौरान, और फिर इसे आपके पास वापस कर देगा। जैसा कि आपने बताया है, बहुत बड़ी फाइलों से निपटने पर यह समस्याग्रस्त है।

यदि आप उत्पन्न होने के दौरान डेटा को संसाधित करना चाहते हैं, तो आपको poll() और .stdout.read() विधियों का उपयोग करके लूप लिखना होगा, फिर उस आउटपुट को किसी अन्य सॉकेट/फ़ाइल/आदि पर लिखें।

ऐसा करने के खिलाफ दस्तावेज में चेतावनी सूचना के लिए सुनिश्चित हो, क्योंकि यह एक गतिरोध में परिणाम के लिए आसान है क्या (मूल प्रक्रिया बच्चे प्रक्रिया डेटा उत्पन्न करने के लिए, है जो बारी में माता-पिता की प्रक्रिया को खाली करने के लिए इंतज़ार कर के लिए इंतजार कर रहा है पाइप बफर)।

1

मैं stdout धारा पर .read() विधि का उपयोग कर रहा था। इसके बजाय, मुझे बस ऊपर लूप के लिए स्ट्रीम से सीधे पढ़ने की जरूरत है। सही कोड जो मैंने अपेक्षित किया है।

#!/usr/bin/env python 
import os 
import sys 
import subprocess 

def main(infile,reflist): 
    print infile,reflist 
    samtoolsin = subprocess.Popen(["samtools","view",infile], 
            stdout=subprocess.PIPE,bufsize=1) 
    samtoolsout = subprocess.Popen(["samtools","import",reflist,"-", 
            infile+".tmp"],stdin=subprocess.PIPE,bufsize=1) 
    for line in samtoolsin.stdout: 
     if(line.startswith("@")): 
      samtoolsout.stdin.write(line) 
     else: 
      linesplit = line.split("\t") 
      if(linesplit[10]=="*"): 
       linesplit[9]="*" 
      samtoolsout.stdin.write("\t".join(linesplit)) 
-1

अजगर में बहुत बड़े निवेश के साथ कुछ बुनियादी खोल पाइपिंग करने के लिए कोशिश कर रहा है:

:

svnadmin load /var/repo < r0-100.dump 

मैं इस बड़े (2-5GB) फ़ाइलों के साथ भी काम कर रहा था पाने के लिए सबसे आसान रास्ता मिल गया

subprocess.check_output('svnadmin load %s < %s' % (repo, fname), shell=True) 

मुझे यह विधि पसंद है क्योंकि यह आसान है और आप मानक खोल पुनर्निर्देशन कर सकते हैं।

मैं एक रीडायरेक्ट को चलाने के लिए popen मार्ग जा रहा करने की कोशिश की:

cmd = 'svnadmin load %s' % repo 
p = Popen(cmd, stdin=PIPE, stdout=PIPE, shell=True) 
with open(fname) as inline: 
    for line in inline: 
     p.communicate(input=line) 

लेकिन वह बड़ी फ़ाइलों के साथ तोड़ दिया। का उपयोग:

p.stdin.write() 

भी बहुत बड़ी फ़ाइलों के साथ तोड़ दिया।

+1

1- एक से अधिक इनपुट के साथ 'p.communicate()' को कॉल करना गलत है (यदि p.communicate() 'रिटर्न 'हो तो बच्चे की प्रक्रिया मर जाती है)। 2- खोल का उपयोग करने की कोई आवश्यकता नहीं है: 'check_call (['svnadmin', 'load', repo], stdin = input_file) 'काम करना चाहिए हालांकि बड़ा' input_file' है। – jfs

+0

@ जेएफ। सेबेस्टियन: जानकारी के लिए धन्यवाद। – mauricio777

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