web-dev-qa-db-ja.com

Python:catサブプロセスを並行して実行する

私はいくつかを実行していますcat | zgrepリモートサーバー上のコマンドと、さらに処理するためにそれらの出力を個別に収集します。

class MainProcessor(mp.Process):
    def __init__(self, peaks_array):
        super(MainProcessor, self).__init__()
        self.peaks_array = peaks_array

    def run(self):
        for peak_arr in self.peaks_array:
            peak_processor = PeakProcessor(peak_arr)
            peak_processor.start()

class PeakProcessor(mp.Process):
    def __init__(self, peak_arr):
        super(PeakProcessor, self).__init__()
        self.peak_arr = peak_arr

    def run(self):
        command = 'ssh remote_Host cat files_to_process | zgrep --mmap "regex" '
        log_lines = (subprocess.check_output(command, Shell=True)).split('\n')
        process_data(log_lines)

ただし、これにより、subprocess( 'ssh ... cat ...')コマンドが順次実行されます。 2番目のピークは、最初のピークが終了するのを待ちます。

サブプロセス呼び出しが並行して実行されるようにこのコードを変更するにはどうすればよいですか?

16
liarspocker

別のアプローチ(シェルプロセスをバックグラウンドに配置するという他の提案ではなく)は、 マルチスレッド を使用することです。

次に、使用しているrunメソッドは次のようになります。

thread.start_new_thread ( myFuncThatDoesZGrep)

結果を収集するには、次のようにします。

class MyThread(threading.Thread):
   def run(self):
       self.finished = False
       # Your code to run the command here.
       blahBlah()
       # When finished....
       self.finished = True
       self.results = []

マルチスレッドのリンクで上記のようにスレッドを実行します。スレッドオブジェクトのmyThread.finished == Trueの場合、myThread.resultsを介して結果を収集できます。

0
FrobberOfBits

サブプロセスを並行して実行するために、multiprocessingthreadingも必要ありません。例:

_#!/usr/bin/env python
from subprocess import Popen

# run commands in parallel
processes = [Popen("echo {i:d}; sleep 2; echo {i:d}".format(i=i), Shell=True)
             for i in range(5)]
# collect statuses
exitcodes = [p.wait() for p in processes]
_

5つのシェルコマンドを同時に実行します。注:ここでは、スレッドもmultiprocessingモジュールも使用されていません。シェルコマンドにアンパサンド_&_を追加する意味はありません。Popenはコマンドが完了するのを待ちません。 .wait()を明示的に呼び出す必要があります。

便利ですが、サブプロセスからの出力を収集するためにスレッドを使用する必要はありません。

_#!/usr/bin/env python
from multiprocessing.dummy import Pool # thread pool
from subprocess import Popen, PIPE, STDOUT

# run commands in parallel
processes = [Popen("echo {i:d}; sleep 2; echo {i:d}".format(i=i), Shell=True,
                   stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
             for i in range(5)]

# collect output in parallel
def get_lines(process):
    return process.communicate()[0].splitlines()

outputs = Pool(len(processes)).map(get_lines, processes)
_

関連: Pythonが複数のbashサブプロセスをスレッド化していますか?

同じスレッド内の複数のサブプロセスから同時に出力を取得するコード例を次に示します。

_#!/usr/bin/env python3
import asyncio
import sys
from asyncio.subprocess import PIPE, STDOUT

@asyncio.coroutine
def get_lines(Shell_command):
    p = yield from asyncio.create_subprocess_Shell(shell_command,
            stdin=PIPE, stdout=PIPE, stderr=STDOUT)
    return (yield from p.communicate())[0].splitlines()

if sys.platform.startswith('win'):
    loop = asyncio.ProactorEventLoop() # for subprocess' pipes on Windows
    asyncio.set_event_loop(loop)
else:
    loop = asyncio.get_event_loop()

# get commands output in parallel
coros = [get_lines('"{e}" -c "print({i:d}); import time; time.sleep({i:d})"'
                    .format(i=i, e=sys.executable)) for i in range(5)]
print(loop.run_until_complete(asyncio.gather(*coros)))
loop.close()
_
33
jfs