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

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

新規登録して質問してみよう
ただいま回答率
86.12%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

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

解決済

joblibでの並列処理の難解点

insecticide
insecticide

総合スコア315

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

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

2回答

0グッド

0クリップ

248閲覧

投稿2022/06/06 22:56

編集2022/06/06 22:58

下記のような並列化処理の場合、sqrt(...)が100回も実行されるので、各実行毎に
下の「accumulator += results」が実行される(100回)のでしょうか、それとも
100回のsqrt(...)が全部実行された後、「accumulator += results」が1回だけ実行されるのでしょうか。

Python

1import joblib 2accumulator = 0 3results = Parallel(delayed(sqrt)(accumulator + i ) for i in range(100)) 4 5accumulator += results 6

以下のような質問にはグッドを送りましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

グッドが多くついた質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

jbpb0

2022/06/06 23:42

> sqrt(...)が100回も実行される のは「results = Parallel(...」の行で、それが全部終わった後に「accumulator += results」は実行されるので、 > 100回のsqrt(...)が全部実行された後、「accumulator += results」が1回だけ実行される でしょう 「Parallel(...」の行以外の行が勝手に100回も実行されたら、困りますよね
insecticide

2022/06/07 01:32 編集

お返事ありがとうございます ❣  💛 > 100回のsqrt(...)が全部実行された後、「accumulator += results」が1回だけ実行される そうしたら、sqrt(...)が100回も実行されたので、一回だけ実行された「accumulator += results」の中のresultsはどのsqrt(...)のリターン値でしょうか。
quickquip

2022/06/07 00:54

動くコードじゃないと質問の意味がない(というか質問にならない)んじゃないでしょうか

回答2

1

こういう説明でわかるでしょうか。

Parallelによる処理は以下のように書かれることが多いです。(質問にあるものは間違えています)

python

1Parallel(n_jobs=3)(delayed(sqrt)(i**2) for i in range(10))

これは2つに分けて考えます。

python

1Parallel(n_jobs=3)

これで、Parallelクラスのインスタンスができます。このインスタンスは与えられえた処理を並列で実行するための仕組みを持っています。この場合は3並列で実行できるようになっています。
変数に束縛すれば使いまわすこともできます。

python

1(delayed(sqrt)(i**2) for i in range(10))

これは、タプルの内包表記ジェネレータ式で、10個のdelayed要素を生成するジェネレタを返します。ジェネレータは読むたびにリストの要素を返すオブジェクトです。
delayedもjoblibの関数で、delayed(A)(B) としたとき、実行すると関数Aに引数としてBを適用します。
そしてParallelのインスタンスに渡すと、これを並列で実行してくれて、それぞれの結果をタプルにして返します。

ということで、質問のやつだと、

python

1results = Parallel(n_jobs=3)(delayed(sqrt)(accumulator + i ) for i in range(100)) 2#↓ 3results = Parallel(n_jobs=3)(delayed(sqrt)(0 + i ) for i in range(100)) 4#↓ 5results = Parallel(n_jobs=3)(delayed(sqrt)(0 + 0), delayed(sqrt)(0 + 1), ... delayed(sqrt)(0 + 99), ) 6#↓ 7results = (0, 1 , 1.41..., 1.73..., 2, ... 9.94...)

のようになって、resultsは このようなタプルになります。

最後の

python

1accumulator += results

がどのような意図で書かれたものなのか、僕にはまったくわかりません。

投稿2022/06/07 02:15

編集2022/06/07 04:18
TakaiY

総合スコア10480

insecticide👍を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

insecticide

2022/06/07 02:37

ご説明上手い ❣ > (delayed(sqrt)(i**2) for i in range(10)) > これは、タプルの内包表記で、10個のdelayed要素のタプルです。 ありがとうございました。
quickquip

2022/06/07 02:50

3つ目のコードブロックのところ、タプルの内包表記ではなくジェネレータ式です。 そうですよね。results = Parallel(...) の行はたぶんこうしたかったんだろうな、と推測できますが、accumulator += results の行はまったくわかりませんよね…。めちゃくちゃ同意でした。
insecticide

2022/06/07 04:15

お返事ありがとうございます。 > 3つ目のコードブロックのところ、タプルの内包表記ではなくジェネレータ式です。 どういうわけでしょうか。 要は実行段階であれば、(..., ..., ...)のような表現はタプルで、それ以前の段階(interpret段階)では《ジェネレータ式》と呼ぶべきでしょうね。
TakaiY

2022/06/07 04:18

指摘ありがとうございます。 僕も勘違いしてました。 回答直しておきました。

0

自己解決

皆さまのご指摘を踏まえて、実例コードを以下のようにしました。

Python

1from joblib import Parallel, delayed 2 3accumulator=55 4 5def testfunc(d1, d2): 6 global accumulator 7 accumulator+=d2 8 return d1,d2,accumulator 9 10 11results = Parallel(n_jobs=-1,verbose=11)(delayed(testfunc)(accumulator, i) for i in range(5)) 12# n_jobsのデフォルトは1(並列処理なし) 13results # [(55, 0, 55), (55, 1, 56), (55, 2, 57), (55, 3, 58), (55, 4, 59)]

上記コードを実行して、resultsは下記の通りでした。
[(55, 0, 55), (55, 1, 56), (55, 2, 57), (55, 3, 58), (55, 4, 59)]

log : Using backend LokyBackend with 2 concurrent workers.

これで分かったのは、
1.global 変数accumulatorは各プロセスの中で値が変えられたにもかかわらず、並列関数の引数としての値はみんな同じ初期値でした。
推測:Parallel 文による関数のタプル化展開(正式の呼び名はジェネレータ式って)は実行前の段階で遂行され、引数も実行前の値ですね。

2.Parallelのreturn変数は必ずlistです。

投稿2022/06/07 03:35

編集2022/06/07 15:46
insecticide

総合スコア315

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

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

ただいまの回答率
86.12%

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

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

質問する

関連した質問

同じタグがついた質問を見る

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

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