2012-03-04 8 views
8

Bazı veri işlemlerini yapmak ve numaralandırma için komut satırı araçlarını çağırmak için Python'u bir komut dosyası dili olarak kullanıyorum. Komut satırı araçlarını birbirlerinden bağımsız oldukları için paralel olarak yürütmek istiyorum. Bir komut satırı aracı bittiğinde, sonuçlarını çıktı dosyasından toplayabilirim. Öyleyse, ana Python programımı bir görevin tamamlandığını bildirmek için bazı senkronizasyon mekanizmalarına da ihtiyacım var, böylece sonuç ana programıma ayrılabilir.Python, komut satırı araçlarını paralel olarak çalıştırıyor

Şu anda, bir iş parçacığı için iyi çalışan ancak paralelleştirilemeyen os.system() kullanıyorum.

Teşekkürler!

+0

Python iyi destek [ 'threading'] (http://docs.python.org/library/threading.html) vardır ve [' multiprocessing'] (http://docs.python.org/ kütüphane/multiprocessing.html). Bunlarla ilgili özel problem nedir? –

cevap

9

multiprocessing modülünden Pool nesnesini kullanın. Daha sonra ör. Paralel işlem yapmak için Pool.map(). Bir örnek, her resim işlemine paralel olarak bir işlevin birden çok kez çağrıldığı markphotos komutumdur (aşağıya bakınız).

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

Teşekkürler! ve her süreçte komut sistemimi aramak için os.system'i kullanabilirim. –

+1

Bunun için daha iyi 'alt işlem' kullan. Bağlantılı örneğe bakın. –

+0

@RolandSmith - Bağlantıyı bir resim dosyasına geri yükleyebilir veya buraya kaynak ekleyebilir misiniz? – keflavich

7

Komut satırı araçlarını ayrı işlemler olarak çalıştırmak isterseniz, bunları senkronize olmayan bir şekilde başlatmak için os.system (veya daha iyisi: The subprocess modülünü) kullanın. Unix Açık/Linux/MacOS:

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

: Bir komut bittiğinde bilerek gelince

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

: unix altında wait vb kurmak alabilir, ama eğer Komut dosyası komut dosyaları yazarken, sadece bir dosyaya bir mesaj yazmaları ve dosyayı çağıran python komut dosyasından izlemelerini istiyorum.

@James Youngman ikinci sorunuza bir çözüm önerdi: Senkronizasyon. Süreçlerinizi python'dan kontrol etmek isterseniz, onları Popen ile eşzamansız olarak başlatabilirsiniz.

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

Eğer POPEN kullanmak ve süreçleri Stdout'a çok veri yazarsanız, programınız kilitlenmeye olacaktır sakının. Tüm çıktıyı bir günlük dosyasına yönlendirdiğinizden emin olun.

p1 ve p2, işlemleriniz üzerinde sekmeleri tutmak için kullanabileceğiniz nesnelerdir. p1.poll() engellenmez, ancak işlem hala devam ediyorsa, Hiçbiri dönmez. Tamamlandığında çıkış durumunu döndürür, böylece sıfır olup olmadığını kontrol edebilirsiniz.

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 

yukarıda sadece bir modeldir: yazılı olarak, çıkış asla ve "hasat" tamamlandı süreçlerin sonuçları tutacak. Ama sana güveniyorum, fikrini al.

+1

Bu test daha genel ve özlü olurdu, eğer varsa [p1, p2] 'de p (p.wait() için):… '. – EOL

+0

Çocuklar, OP hesaplamaları eşzamansız olarak çalıştırmak ve sonuçları toplamak istiyor. "Bir Python programımı bir görev tamamlandığını bildirmek için" bir yol istiyor. Tüm çocuklar bitene kadar bekleyin() engelleyecektir. – alexis

+0

@James Youngman: Değişikliklerinizi geri aldığım için üzgünüz. Onların tarihten kaybolmalarını beklemiyordum. Onları cevaba dahil ettim (görebildiğiniz gibi, ayrı sorunlara sahip ayrı bir çözüm). – alexis