これは同様の文脈で尋ねられたかもしれませんが、約20分間の検索で答えを見つけることができなかったので、尋ねます。
Pythonスクリプト(scriptA.pyと言う)とスクリプト(scriptB.pyと言う)を作成しました
ScriptBでは、異なる引数を使用してscriptAを複数回呼び出し、そのたびに実行に約1時間かかります(その巨大なスクリプトで、多くのことを行います。心配する必要はありません)。 scriptAにすべての異なる引数を同時に指定しますが、続行する前にすべての引数が完了するまで待つ必要があります。私のコード:
import subprocess
#setup
do_setup()
#run scriptA
subprocess.call(scriptA + argumentsA)
subprocess.call(scriptA + argumentsB)
subprocess.call(scriptA + argumentsC)
#finish
do_finish()
すべてのsubprocess.call()
を同時に実行し、すべてが完了するまで待ちたいのですが、どうすればよいですか?
例のようにスレッドを使用しようとしました here :
from threading import Thread
import subprocess
def call_script(args)
subprocess.call(args)
#run scriptA
t1 = Thread(target=call_script, args=(scriptA + argumentsA))
t2 = Thread(target=call_script, args=(scriptA + argumentsB))
t3 = Thread(target=call_script, args=(scriptA + argumentsC))
t1.start()
t2.start()
t3.start()
しかし、私はこれが正しいとは思わない。
do_finish()
に移動する前に、すべての実行が完了したことをどのようにして確認できますか?
スクリプトの最後でThread
オブジェクトの join メソッドを使用する必要があります。
t1 = Thread(target=call_script, args=(scriptA + argumentsA))
t2 = Thread(target=call_script, args=(scriptA + argumentsB))
t3 = Thread(target=call_script, args=(scriptA + argumentsC))
t1.start()
t2.start()
t3.start()
t1.join()
t2.join()
t3.join()
したがって、メインスレッドは、t1
、t2
、およびt3
の実行が完了するまで待機します。
スレッドをリストに入れてから Join method を使用します
threads = []
t = Thread(...)
threads.append(t)
...repeat as often as necessary...
# Start all threads
for x in threads:
x.start()
# Wait for all of them to finish
for x in threads:
x.join()
入力リストに基づいたリスト内包表記の使用を好みます:
inputs = [scriptA + argumentsA, scriptA + argumentsB, ...]
threads = [Thread(target=call_script, args=(i)) for i in inputs]
[t.start() for t in threads]
[t.join() for t in threads]
Python3では、Python 3.2以降、同じ結果に到達するための新しいアプローチがあり、個人的には従来のスレッドの作成/開始/結合、パッケージconcurrent.futures
: https:// docs。 python.org/3/library/concurrent.futures.html
ThreadPoolExecutor
を使用すると、コードは次のようになります。
from concurrent.futures.thread import ThreadPoolExecutor
import time
def call_script(ordinal, arg):
print('Thread', ordinal, 'argument:', arg)
time.sleep(2)
print('Thread', ordinal, 'Finished')
args = ['argumentsA', 'argumentsB', 'argumentsC']
with ThreadPoolExecutor(max_workers=2) as executor:
ordinal = 1
for arg in args:
executor.submit(call_script, ordinal, arg)
ordinal += 1
print('All tasks has been finished')
前のコードの出力は次のようなものです。
Thread 1 argument: argumentsA
Thread 2 argument: argumentsB
Thread 1 Finished
Thread 2 Finished
Thread 3 argument: argumentsC
Thread 3 Finished
All tasks has been finished
利点の1つは、最大同時ワーカー数を設定するスループットを制御できることです。
以下のようなクラスを使用して、並列情熱で実行する「n」個の関数またはconsole_scriptsを追加し、実行を開始してすべてのジョブが完了するのを待つことができます。
from multiprocessing import Process
class ProcessParallel(object):
"""
To Process the functions parallely
"""
def __init__(self, *jobs):
"""
"""
self.jobs = jobs
self.processes = []
def fork_processes(self):
"""
Creates the process objects for given function deligates
"""
for job in self.jobs:
proc = Process(target=job)
self.processes.append(proc)
def start_all(self):
"""
Starts the functions process all together.
"""
for proc in self.processes:
proc.start()
def join_all(self):
"""
Waits untill all the functions executed.
"""
for proc in self.processes:
proc.join()
def two_sum(a=2, b=2):
return a + b
def multiply(a=2, b=2):
return a * b
#How to run:
if __== '__main__':
#note: two_sum, multiply can be replace with any python console scripts which
#you wanted to run parallel..
procs = ProcessParallel(two_sum, multiply)
#Add all the process in list
procs.fork_processes()
#starts process execution
procs.start_all()
#wait until all the process got executed
procs.join_all()
threading
から モジュールのドキュメント
「メインスレッド」オブジェクトがあります。これは、Pythonプログラムの制御の初期スレッドに対応します。デーモンスレッドではありません。
「ダミースレッドオブジェクト」が作成される可能性があります。これらは、「エイリアンスレッド」に対応するスレッドオブジェクトです。これは、Cコードから直接など、スレッドモジュールの外部で開始される制御のスレッドです。ダミースレッドオブジェクトの機能は制限されています。それらは常に生きていてデーモンであると見なされ、
join()
edにすることはできません。エイリアンスレッドの終了を検出することは不可能なので、削除されません。
したがって、作成するスレッドのリストを保持することに興味がない場合に、これらの2つのケースをキャッチするには:
import threading as thrd
def alter_data(data, index):
data[index] *= 2
data = [0, 2, 6, 20]
for i, value in enumerate(data):
thrd.Thread(target=alter_data, args=[data, i]).start()
for thread in thrd.enumerate():
if thread.daemon:
continue
try:
thread.join()
except RuntimeError as err:
if 'cannot join current thread' in err.args[0]:
# catchs main thread
continue
else:
raise
すぐに:
>>> print(data)
[0, 4, 12, 40]
たぶん、次のようなもの
for t in threading.enumerate():
if t.daemon:
t.join()
Forループを使用して作成されたすべてのスレッドを待つ必要があるという同じ問題に遭遇しました。次のコードを試してみました。完璧な解決策ではないかもしれませんが、単純な解決策だと思いましたテストする:
for t in threading.enumerate():
try:
t.join()
except RuntimeError as err:
if 'cannot join current thread' in err:
continue
else:
raise