(133) 複数プロセスに振り分けた処理の進捗状況をプログレスバーで表示する。

投稿者: | 2025年6月4日

91 views

【1】やりたいこと

重たい処理を複数プロセスに分担させ、高速実行したい場合はよくある。

このとき、
マルチプロセスで実行している処理の進捗状況を、1本のプログレスバーに表示したい
と思った。

過去記事 (131) tqdm.trangeで簡単にプログレスバーを表示する。 でインストールしたばかりの
tqdmを使えばこれが簡単に実現できる らしいと聞いたので、試してみることにした。

【2】やってみた

1) プログラムソースコード

以下のコマンドラインオプションを用意した。

optiontype説明
-nint並列実行プロセス数を指定する。

from multiprocessing import Pool
from itertools import product
from tqdm import tqdm                       # 進捗バー表示用
from datetime import datetime               # 現在日時を取得するためのライブラリ
import argparse

#///////////////////////////////////////////////////////////////////////////////
# 各プロセスに実行させるダミーの重たい処理
def heavy_calculation(n):                   # nを素因数分解する(単純な試し割り法)
    factors = []
    i = 2
    while i * i <= n:
        while n % i == 0:
            factors.append(i)
            n //= i
        i += 1
    if n > 1:
        factors.append(n)
    return factors

#///////////////////////////////////////////////////////////////////////////////
# 各プロセスが分担する処理のエントリポイント
def processProc( param ):
    vA, vB = param
    factors = []
    for i in range(1000):
        n = (vA + vB) * (i + 1) * 10**6
        factors += heavy_calculation(n)
    return sum(factors)                     # 素因数の合計を返す

#///////////////////////////////////////////////////////////////////////////////
if __name__ == "__main__":
    #---------------------------------------------------------------------------
    # コマンドライン引数を取得
    parser = argparse.ArgumentParser(description="test")
    parser.add_argument('-n', type=int, help='プロセス数', default=1)
    args = parser.parse_args()
    #---------------------------------------------------------------------------
    # データ初期化
    n_process = args.n                      # 並列で動かすプロセス数
    vAs = range(1, 101)                     # 要素数100個の配列(1,2,3,4,...,98,99,100)
    vBs = range(1, 101)                     # 要素数100個の配列(1,2,3,4,...,98,99,100)
    # vAsと vBsの全要素の組合せ(100×100=10000通り)を作成
    params   = list(product(vAs, vBs))
    n_params = len(params)
    total_sum = 0                           # 全結果の合計値を格納
    start_time = datetime.now()             # 開始時刻を記録
    #--------------------------------------------------------------------------->>> 並列処理区間
    with Pool( n_process ) as pool:         # プロセスプールを作成
        # paramsの 1要素ずつ各プロセスに処理させる。
        results_iterator = pool.imap_unordered( processProc, params )
        # tqdmで進捗バーを表示する。
        for res in tqdm( results_iterator, total=n_params ):
            total_sum += res                # 各結果を合計に加算
    #---------------------------------------------------------------------------<<< 並列処理区間
    end_time = datetime.now()               # 終了時刻を記録
    duration = end_time - start_time
    # 最終結果を表示
    print(f"全組合せの加算結果の合計値: {total_sum}")   # 正しく処理されたことを確認するため
    print(f"実行時間: {duration.total_seconds():.1f}")  # 並列化で高速化することを確認

2) 実行結果

実行環境の CPUが Intel Core Ultla 265KF(20core) なので、最大 20コア指定で実行してみた。

20コア、15コア、10コア、8コア、4コア、2コア、1コア 指定で上記のプログラムを実行してみた。
いずれの場合も同じように 1本のプログレスバーが伸びる様子を確認 できた。

$ python main_00133.py -n 20
100%|█████████████████████████████████████████████| 10000/10000 [00:00<00:00, 14855.35it/s]
全組合せの加算結果の合計値: 2248942000
実行時間: 0.7 sec

$ python main_00133.py -n 15
100%|█████████████████████████████████████████████| 10000/10000 [00:00<00:00, 12148.88it/s]
全組合せの加算結果の合計値: 2248942000
実行時間: 0.8 sec

$ python main_00133.py -n 10
100%|█████████████████████████████████████████████| 10000/10000 [00:01<00:00, 8506.88it/s]
全組合せの加算結果の合計値: 2248942000
実行時間: 1.2 sec

$ python main_00133.py -n 8
100%|█████████████████████████████████████████████| 10000/10000 [00:01<00:00, 7049.92it/s]
全組合せの加算結果の合計値: 2248942000
実行時間: 1.4 sec

$ python main_00133.py -n 4
100%|█████████████████████████████████████████████| 10000/10000 [00:02<00:00, 3530.27it/s]
全組合せの加算結果の合計値: 2248942000
実行時間: 2.8 sec

$ python main_00133.py -n 2
100%|█████████████████████████████████████████████| 10000/10000 [00:05<00:00, 1749.37it/s]
全組合せの加算結果の合計値: 2248942000
実行時間: 5.7 sec

$ python main_00133.py -n 1
100%|█████████████████████████████████████████████| 10000/10000 [00:11<00:00, 893.68it/s]
全組合せの加算結果の合計値: 2248942000
実行時間: 11.2 sec

プログレスバーの右端に表示されている 893.68it/s は、
1秒当たりの実行された iteration数 だ。
今回の場合、全10000セットのデータを 1秒につき何セット処理できたかを表す。

例えば、2コア指定で実行した場合の 1749.37it/s を確かめてみると、
10000回 ÷ 5.7秒 = 1754.3回/秒
だいたい同じだ。
プログレスバーは、進捗状況をざっくりと眺めることが目的の indicator なので、時間値の精度は気にしない。


アクセス数(直近7日): ※試験運用中、BOT除外簡易実装済
  • 2025-07-11: 0回
  • 2025-07-10: 2回
  • 2025-07-09: 2回
  • 2025-07-08: 3回
  • 2025-07-07: 0回
  • 2025-07-06: 0回
  • 2025-07-05: 0回
  • コメントを残す

    メールアドレスが公開されることはありません。 が付いている欄は必須項目です