2012-03-04 10 views
8

私はいくつかのデータ処理を行い、数値処理のためにコマンドラインツールを呼び出すためにPythonをスクリプト言語として使用しています。私はコマンドラインツールを互いに独立しているので並列に実行したいと考えています。 1つのコマンドラインツールが終了すると、その結果を出力ファイルから収集することができます。ですから、メインのPythonプログラムに、あるタスクが終了したことを通知して、その結果が私のメインプログラムに解析されるようにする同期メカニズムも必要です。コマンドラインツールを並列に実行しているPython

現在のところ、私はos.system()を使用していますが、これは1スレッドで正常に動作しますが、並列化できません。

ありがとうございます!

+0

Pythonは[ 'threading'(http://docs.python.org/library/threading.html)のための良好なサポートを有し、[' multiprocessing'(http://docs.python.org/ライブラリ/ multiprocessing.html)。あなたはそれらの特有の問題は何ですか? –

答えて

9

multiprocessingモジュールのPoolオブジェクトを使用してください。たとえば、 Pool.map()は並列処理を行います。一例として、私のmarkphotosスクリプト(下記参照)があります。ここでは、関数はピクチャの各処理と並行して複数回呼び出されます。

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

ありがとう!それぞれのプロセスで 'os.system'を使ってコマンドラインを呼び出すことができますか? –

+1

それには 'subprocess'を使うのが良いです。リンクされた例を参照してください。 –

+0

@RolandSmith - markphotosへのリンクを復元するか、ここにソースを追加できますか? – keflavich

7

コマンドラインツールを別のプロセスとして実行する場合は、os.system(またはそれ以上のモジュール:subprocessモジュール)を使用して非同期で開始してください。 UNIXの場合/ Linuxの/ MacOSの:

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

:コマンドが終了したときを知るためのよう

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

:UNIXであなたがwaitなどで設定を取得できますが、あなたがしている場合コマンドラインスクリプトを書くだけで、ファイルにメッセージを書き込ませ、呼び出したpythonスクリプトからファイルを監視するようにしています。

@James Youngmanは、2番目の質問に対する解決策を提案しました。あなたのプロセスをPythonから制御したいのであれば、Popenと非同期にプロセスを開始することができます。

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

Popenを使用し、プロセスがstdoutに大量のデータを書き込むと、プログラムがデッドロックすることに注意してください。すべての出力を必ずログファイルにリダイレクトしてください。

p1およびp2は、プロセスを監視するために使用できるオブジェクトです。 p1.poll()はブロックしませんが、プロセスがまだ実行中の場合はNoneを返します。終了時に終了ステータスを返すので、ゼロであるかどうかを確認できます。

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

テストはより一般的で簡潔です。もしあれば([p1、p2]のpのためのp.wait()):... '。 – EOL

+0

皆さん、OPは計算を非同期で実行し、結果を収穫したいと考えています。彼は、 "私のメインPythonプログラムに1つのタスクが完了したことを通知する"方法を望んでいます。 wait()はすべての子が終了するまでブロックします。 – alexis

+0

@ James Youngman:変更をロールバックして申し訳ありません。私は彼らが歴史から消えることを期待していませんでした。私は答えにそれらを含めました(あなたが見ることができるように、それは別々の問題を持つ別個の解決策です)。 – alexis

関連する問題