2012-03-04 14 views
8

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

वर्तमान में, मैं os.system() का उपयोग करता हूं, जो एक थ्रेड के लिए ठीक काम करता है, लेकिन समानांतर नहीं किया जा सकता है।

धन्यवाद!

+0

अजगर [ 'threading'] (http://docs.python.org/library/threading.html) के लिए अच्छा समर्थन और है [' multiprocessing'] (http://docs.python.org/ पुस्तकालय/multiprocessing.html)। उन लोगों के साथ आपकी विशिष्ट समस्या क्या है? –

उत्तर

9

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

#! /usr/bin/env python 
# -*- coding: utf-8 -*- 
# Adds my copyright notice to photos. 
# 
# Author: R.F. Smith <[email protected]> 
# $Date: 2012-10-28 17:00:24 +0100 $ 
# 
# To the extent possible under law, Roland Smith has waived all copyright and 
# related or neighboring rights to markphotos.py. This work is published from 
# the Netherlands. See http://creativecommons.org/publicdomain/zero/1.0/ 

import sys 
import subprocess 
from multiprocessing import Pool, Lock 
from os import utime, devnull 
import os.path 
from time import mktime 

globallock = Lock() 

def processfile(name): 
    """Adds copyright notice to the file. 

    Arguments: 
    name -- file to modify 
    """ 
    args = ['exiftool', '-CreateDate', name] 
    createdate = subprocess.check_output(args) 
    fields = createdate.split(":") #pylint: disable=E1103 
    year = int(fields[1]) 
    cr = "R.F. Smith <[email protected]> http://rsmith.home.xs4all.nl/" 
    cmt = "Copyright © {} {}".format(year, cr) 
    args = ['exiftool', '-Copyright="Copyright (C) {} {}"'.format(year, cr), 
      '-Comment="{}"'.format(cmt), '-overwrite_original', '-q', name] 
    rv = subprocess.call(args) 
    modtime = int(mktime((year, int(fields[2]), int(fields[3][:2]), 
          int(fields[3][3:]), int(fields[4]), int(fields[5]), 
          0,0,-1))) 
    utime(name, (modtime, modtime)) 
    globallock.acquire() 
    if rv == 0: 
     print "File '{}' processed.".format(name) 
    else: 
     print "Error when processing file '{}'".format(name) 
    globallock.release() 

def checkfor(args): 
    """Make sure that a program necessary for using this script is 
    available. 

    Arguments: 
    args -- list of commands to pass to subprocess.call. 
    """ 
    if isinstance(args, str): 
     args = args.split() 
    try: 
     with open(devnull, 'w') as f: 
      subprocess.call(args, stderr=subprocess.STDOUT, stdout=f) 
    except: 
     print "Required program '{}' not found! exiting.".format(args[0]) 
     sys.exit(1) 

def main(argv): 
    """Main program. 

    Arguments: 
    argv -- command line arguments 
    """ 
    if len(argv) == 1: 
     binary = os.path.basename(argv[0]) 
     print "Usage: {} [file ...]".format(binary) 
     sys.exit(0) 
    checkfor(['exiftool', '-ver']) 
    p = Pool() 
    p.map(processfile, argv[1:]) 
    p.close() 

if __name__ == '__main__': 
    main(sys.argv) 
+0

धन्यवाद! और ऐसा लगता है कि प्रत्येक प्रक्रिया में, मैं अपनी कमांड लाइन को कॉल करने के लिए 'ओएस सिस्टम' का उपयोग कर सकता हूं? –

+1

उस के लिए बेहतर 'subprocess' का उपयोग करें। लिंक किए गए उदाहरण देखें। –

+0

@ रोलैंडस्मिथ - क्या आप मार्कफोटोस को लिंक पुनर्स्थापित कर सकते हैं या यहां स्रोत जोड़ सकते हैं? – keflavich

7

यदि आप कमांडलाइन उपकरण को अलग प्रक्रियाओं के रूप में चलाने के लिए चाहते हैं, तो बस os.system (या बेहतर: subprocess मॉड्यूल) का उपयोग अतुल्यकालिक रूप से शुरू करने के लिए करें। यूनिक्स पर/linux/MacOS:

subprocess.call("command -flags arguments &", shell=True) 

विंडोज पर:

subprocess.call("start command -flags arguments", shell=True) 

जब एक आदेश समाप्त हो गया है जानने के लिए के रूप में: यूनिक्स के अंतर्गत आप wait आदि के साथ स्थापित हो सकता है, लेकिन अगर आप कर रहे हैं कमांडलाइन स्क्रिप्ट लिखना, मैं बस उन्हें एक फ़ाइल में एक संदेश लिखूंगा, और कॉलिंग पायथन स्क्रिप्ट से फ़ाइल की निगरानी करूंगा।

@ जेम्स यंगमैन ने आपके दूसरे प्रश्न का समाधान प्रस्तावित किया: सिंक्रनाइज़ेशन। यदि आप अपनी प्रक्रियाओं को पायथन से नियंत्रित करना चाहते हैं, तो आप उन्हें पॉपन के साथ असीमित रूप से शुरू कर सकते हैं।

p1 = subprocess.Popen("command1 -flags arguments") 
p2 = subprocess.Popen("command2 -flags arguments") 

सावधान रहें कि यदि आप popen का उपयोग करें और अपनी प्रक्रियाओं stdout में काफी मात्रा में डेटा लिखते हैं, अपने कार्यक्रम गतिरोध होगा। सभी आउटपुट को लॉग फ़ाइल में रीडायरेक्ट करना सुनिश्चित करें।

p1 और p2 वे ऑब्जेक्ट्स हैं जिनका उपयोग आप अपनी प्रक्रियाओं पर टैब रखने के लिए कर सकते हैं। p1.poll() अवरुद्ध नहीं होगा, लेकिन अगर प्रक्रिया अभी भी चल रही है तो कोई भी वापस नहीं आएगा। जब यह किया जाता है तो यह बाहर निकलने की स्थिति वापस कर देगा, ताकि आप जांच सकें कि यह शून्य है या नहीं।

for proc in [p1, p2]: 
    time.sleep(60) 
    status = proc.poll() 
    if status == None: 
     continue 
    elif status == 0: 
     # harvest the answers 
    else: 
     print "command1 failed with status", status 

ऊपर सिर्फ एक मॉडल है: लिखित रूप में, यह बाहर निकलने कभी नहीं होगा, और यह "कटाई" पूरा प्रक्रियाओं के परिणाम रखेंगे। लेकिन मुझे विश्वास है कि आपको विचार मिल गया है।

+1

परीक्षण अधिक सामान्य और संक्षेप में होगा यदि 'पी 1, पी 2] में पी के लिए कोई (पी। वाइट()): ... '। – EOL

+0

दोस्तों, ओपी संकलन को अतुल्यकालिक रूप से चलाने और परिणामों को फसल करना चाहता है। वह एक तरीका चाहता है "मेरे मुख्य पायथन कार्यक्रम को सूचित करने के लिए कि एक कार्य समाप्त हो गया है"। प्रतीक्षा करें() तब तक अवरुद्ध हो जाएंगे जब तक कि सभी बच्चे समाप्त नहीं हो जाते। – alexis

+0

@ जेम्स यमैन: अपने बदलावों को वापस लाने के लिए खेद है। मैंने उन्हें इतिहास से गायब होने की उम्मीद नहीं की थी। मैंने उन्हें जवाब में शामिल किया (जैसा कि आप देख सकते हैं, यह अलग-अलग मुद्दों के साथ एक अलग समाधान है)। – alexis