1
2

More than 3 years have passed since last update.

multiprocessingによる複数引数とプロセス数指定に対応した並列処理[PDF保存]

Last updated at Posted at 2020-08-22

背景

ある測定データ(csv)のグラフをPDFで保存したかった。
データ数が多く(1000データ)なると時間がたくさん(8minほど)かかってしまったので改善しようと思った。

目的

大量のPDFの保存を高速かつ、動作時にPCが固まらないようにしたい。

手法

pythonを用いて主に以下のことをした。

  1. 全測定データ(csv)を参照
  2. 全測定データを配列に保存
  3. 全測定条件データを読み込み
  4. ひとデータごとに全データでループ ← これを高速化
    1. 測定データ・測定条件を受け取り(引数が複数)
    2. matplotで描写
    3. PDFで保存

そのまま

pythonで普通にfor loop

Treading

諸事情で実装経験があったのでやってみた
→こいつは1コアしか使えないので速度は大きく変わらない模様。
それでも4minも変わるのは意外

multiprocessing.Process

並列処理したい関数に引数が複数あるので、Processを利用した。
しかしいくらggってもスレッド数の制限方法が分からず、それは実装できなかった。
そのせいで、実行すると1000個の並列処理をするのでPCがカクカクになってしまった。

multiprocessing.Pool

引数は1つしか持てないが、スレッド数を簡単に指定できる。
以下のような関数をカマス事で複数引数にも対応できた。

def wrapper(self, args):
    return self.f(*args)

コーディング

multiprocessingのコーディングは以下のようにやればOK。
コーディングの仕方だけがわかる最小構成(並列化の意味はない)ものです。
詳細はこの記事などが参考になります。
Pythonの並列処理・並行処理をしっかり調べてみた - Qiita

from multiprocessing import Process, Pool
import multiprocessing

def f(a, b): # 並列処理する関数
    print(a, end=",") # 動作確認だけなのでシンプルに

def wrapper(args):  # Poolは引数を1つしか取れないので、これをかまして展開する。
    f(*args)

def main():
    # Processによる並列処理(複数引数:o, プロセス数指定:x)
    print('Process')
    p_list = []
    for i in range(20):
        p = Process(
            target=f,
            kwargs={'a': i, 'b': 0})
        p.start()  # 開始
        p_list.append(p)

    for p in p_list:
        p.join()  # 終了を待つ

    # Poolによる並列処理(複数引数:x, プロセス数指定:o)
    print('\nPool')
    p = Pool(multiprocessing.cpu_count())  # CPUの数の分並列処理
    values = []

    for i in range(20):
        values.append((i, 0))
    p.map(wrapper, values)  # 単数引数を複数に展開する

if __name__ == "__main__":
    main()

結果

Process
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,
Pool
6,0,8,14,2,10,16,3,11,17,5,13,18,1,9,15,4,12,19,7,

結論

動作時間

以下のような順位になりました。

  1. multiprocessing(Poolによりスレッド数をPCのコア数に制限) 1min 50sec
  2. multiprocessing(スレッド数の制限なし) 4min 30sec程度
  3. threading 5min 41sec
  4. 並列化なし(pythonによる自動並列?のみ) 9min 33sec

※試行錯誤の過程のメモなので、同等の条件で測定していない場合があります。目安程度に。

考察

1.と2.の比較をします。
1.は8個ずつ順に処理を進める事になります。

2.は全処理(今回は1000の処理)を同時並行で行う事になります。

  • 2.の方が早くなるはずではないのか?
    実は、CPUは原理的に並列処理が不可能。
    並列処理思われているものは、実は代わる代わるやることを変えているだけ。
    例えば処理1、2、3の並列処理は
    処理1(1μs実行)→処理2(1μs実行)→処理3(1μs実行)→処理1(さっきの続きから1μs実行)→・・・
    というように並列に見せかけているだけである。
    よって
    処理1(終わるまで実行)→処理2(終わるまで実行)→処理3(終わるまで実行)
    としても原理的には時間は変わらない。(こともある)
    ただ、コア数(CPUの数)の分だけは並列処理が出来るので、それまでは処理が早くなる。

  • なぜ早くなったのか?
    メモリが豊富に使えるようになったから?
    2.では1000の処理をやっているのでメモリがカツカツになってしまう。
    そこが改善されたからではないか?

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2