質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
並列処理

複数の計算が同時に実行される手法

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

2回答

1189閲覧

Python3 multiprocessingを用いた一部分の並列化

tthk

総合スコア11

並列処理

複数の計算が同時に実行される手法

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2020/01/10 15:19

編集2020/01/10 15:20

前提・実現したいこと

multiprocessing.Pool で一部分を並列化したいと考えております.
以下に簡略化したプログラムを示します.

並列化したい関数

python

1import multiprocessing 2from multiprocessing import Pool 3 4def func1(num): 5 li = [] 6 for a in range(num): 7 for b in range(a, a*2): 8 for c in range(a, a*3): 9 d = func2(a, b, c) # TrueかFalseが返る 10 if d: 11 li.append([a, b, c]) 12 if li != []: 13 break 14 return li

このプログラムで伝えたいことは
・上から2つ目と3つめ目のforループのb, cはaによって決まる(実際はrange(数値)ではありません)
・func1の目的は,条件を満たす(func2でTrueが返る)最小のaとその組b, cを求める
ということです.

試したこと

以下のように並列化してみました.

python

1def mult_func1(num): # func1の並列化 2 for a in range(num): 3 target = [] 4 for b in range(a, a*2): 5 for c in range(a, a*3): 6 target.append((a, b, c)) 7 with Pool(multiprocessing.cpu_count()) as pool: 8 result = pool.starmap(func3, target) 9 pool.close() 10 result = [x for x in result if x] # 空リストを削除 11 if result != []: 12 break 13 return result 14 15def func3(a, b, c): 16 d = func2(a, b, c) 17 if d: 18 return a, b, c 19 else: 20 return []

しかし,このプログラムは並列化する前よりも倍以上実行時間がかかってしまいました.
forループの中に並列化処理を入れているせいで遅くなってしまっていると思いますが,どのように解決したらよいでしょうか?
numは大きい値のため,3重ループを並列化処理して,すべての処理が終わった後に最小のaの組を取り出すという操作は避けたいです.
よろしくお願いいたします.

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

python

1def mult_func1(num): # func1の並列化 2 for a in range(num): 3 target = [] 4 for b in range(a, a*2): 5 for c in range(a, a*3): 6 target.append((a, b, c)) 7 with Pool(multiprocessing.cpu_count()) as pool: 8 result = pool.starmap(func3, target) 9 pool.close() 10 result = [x for x in result if x] # 空リストを削除 11 if result != []: 12 break 13 return result 14 15def func3(a, b, c): 16 d = func2(a, b, c) 17 if d: 18 return a, b, c 19 else: 20 return [] 21

上記コードですと、プロセス数分同じ処理(計算)していませんか?

python

1result = pool.starmap(func3, target)

この後のresultの値を確認してください。重複していないでしょうか?

投稿2020/01/11 00:51

編集2020/01/11 13:46
meg_

総合スコア10580

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tthk

2020/01/11 03:38

ご回答いただきありがとうございます. 確かに簡略化していない元のプログラムでは重複していたのですが,上記のプログラムでtargetを出力したり適当なfunc2を作ってresultを出力したりしましたが,なぜか重複が見られませんでした. この試行も含め根本的に何か間違っている気がいたしますが,重複する原因がわからないので教えていただけないでしょうか?
tthk

2020/01/11 07:44

何度もすみません. もう一度よく確認したところ,元のプログラムでも重複はありませんでした. ただ,resultが上書きされているだけで処理自体が複数行われているのかなとも思ったのですが,プロセス数分同じ処理をしているというお考えに至った理由をお聞かせいただけますでしょうか?
meg_

2020/01/11 13:48

pool.starmap()に対する理解が足りていませんでした。すみません。 ただ、マルチプロセス化したのに遅くなるのは謎ですね。検証可能なコードを提示いただくことは可能でしょうか?
tthk

2020/01/12 05:26

ご返信ありがとうございます. func3にtime.sleep(1)を入れると並列化した場合に早くなったので,func3の処理が軽すぎることが原因かなと思いました.なので,並列化ではなくforループを高速化することに切り替えたいと思います. 紳士に対応してくださりありがとうございました.
guest

0

三段階の for ループがありますが、入力データをパラメータにするのではなく、2段階目と3段階目の for ループ func3() に含めたらどうでしょうか?

投稿2020/01/10 15:40

編集2020/01/10 15:44
mmaeda

総合スコア269

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tthk

2020/01/11 07:59

ご回答いただきありがとうございます. 2段階目と3段階目の for ループ をfunc3() に含めるということは with Pool(multiprocessing.cpu_count()) as pool: result = pool.map(func3, range(num)) と書き換えるという理解で合ってますでしょうか? 確かに,forループのなかに並列化処理を入れることを避けられますが,結局3重ループを並列計算していることと同じですので,この手法は避けたいと考えております.(そのように意図されていなかったらすみません) ただ,range(num)=[0 1 2 3]として0, 1, 2, 3が並列化処理されているとしたときに,それぞれの結果をマージされる前に確認して,条件を満たしていれば並列化処理を強制的に止める,ということができれば実現可能なのではと思ったのですが,そのようなことは可能なのでしょうか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問