終了待ち - python マルチスレッド 終了




すべてのスレッドが終了するまで、Pythonのマルチスレッドを待つ (6)

これは同様の文脈で尋ねられたかもしれませんが、約20分の検索の後で答えを見つけることができなかったので、私は尋ねます。

私はPythonスクリプト(scriptA.pyと言うことができます)とスクリプト(scriptB.pyと言うことができます)を書いています。

スクリプトBでは、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の例のようなスレッドを使用しようとし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()に行く前に、それらがすべて終了したことをどのように知っていますか?


Python3では、Python 3.2以降、私は個人的には従来のスレッドの作成/開始/結合、 concurrent.futuresパッケージconcurrent.futureshttps://docs.python.org/3/library/concurrent.futures.html ://docs.python.org/3/library/に同じ結果に到達する新しいアプローチがありhttps://docs.python.org/3/library/concurrent.futures.html

ThreadPoolExecutorを使用すると、コードは次のようになります。

from concurrent.futures.thread import ThreadPoolExecutor

def call_script(arg)
    subprocess.call(scriptA + arg)

args = [argumentsA, argumentsB, argumentsC]
with ThreadPoolExecutor(max_workers=2) as executor:
    for arg in args:
        executor.submit(call_script, arg)
print('All tasks has been finished')

利点の1つは、スループットを最大並行作業者に設定できることです。


threading モジュールのドキュメントから

「メインスレッド」オブジェクトがあります。 これはPythonプログラムの初期制御スレッドに対応しています。 これはデーモンスレッドではありません。

ダミースレッドオブジェクトが作成される可能性があります。 これらは、「エイリアンスレッド」に対応するスレッドオブジェクトであり、Cコードから直接など、スレッドモジュール外で開始される制御スレッドです。 ダミーのスレッドオブジェクトには機能が制限されています。 彼らは常に生き生きとデーモンとみなされ、 join()ことはできません。 エイリアンスレッドの終了を検出することは不可能であるため、これらは削除されません。

したがって、あなたが作成したスレッドのリストを保持することに興味がない場合、これらの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]

スレッドをリストに入れて、 Joinメソッドを使用する

 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()

多分、何かのように

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

私は入力リストに基づいてリストの理解を使用することを好む:

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]




multithreading