🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Google Colaboratory

Google Colaboratoryとは、無償のJupyterノートブック環境。教育や研究機関の機械学習の普及のためのGoogleの研究プロジェクトです。PythonやNumpyといった機械学習で要する大方の環境がすでに構築されており、コードの記述・実行、解析の保存・共有などが可能です。

並列処理

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

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

Python

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

Google

Googleは、アメリカ合衆国に位置する、インターネット関連のサービスや製品を提供している企業です。検索エンジンからアプリケーションの提供まで、多岐にわたるサービスを提供しています。

Q&A

解決済

3回答

4900閲覧

複数の並列処理を入れ子構造で動かしたい。

hiroki91629

総合スコア3

Google Colaboratory

Google Colaboratoryとは、無償のJupyterノートブック環境。教育や研究機関の機械学習の普及のためのGoogleの研究プロジェクトです。PythonやNumpyといった機械学習で要する大方の環境がすでに構築されており、コードの記述・実行、解析の保存・共有などが可能です。

並列処理

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

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

Python

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

Google

Googleは、アメリカ合衆国に位置する、インターネット関連のサービスや製品を提供している企業です。検索エンジンからアプリケーションの提供まで、多岐にわたるサービスを提供しています。

0グッド

0クリップ

投稿2021/03/13 09:55

編集2021/03/16 02:32

前提・実現したいこと

複数の並列処理を入れ子構造で動かしたい。

一様分布の乱数を任意の回数処理するのを任意の回数行う
具体的イメージ:ランダム性のあるレース(ネズミの競争)を6レース分並列処理すること
レーサーの数は3とする。

###目的
複数の並列処理を入れ子構造で動かし、なるべく短時間で処理を行えるようにしたい。

知りたい事

下記コードが進行不可能な理由。←解決
下記コードを動かす改善方法。
他の有効な並列演算方法はあるかどうか。
daemonic processesとは何か。
追記:プロセッシングしてスレッディングすれば解決の可能性があるかもしれないとの事なので、サンプルコードを組んでいただけると助かります。
自身でもやってみます。

###環境
google cocolaboratory

発生している問題・エラーメッセージ

エラーメッセージ AssertionError: daemonic processes are not allowed to have children

該当のソースコード

Python

1ソースコード 2 3import pandas 4import random 5from multiprocessing import Pool 6 7#####一様な乱数に従って任意回数思考した後、着順を返す関数の定義##### 8def try_def(try_times): 9 count = 3#count:レーサーの数 10 #要素数:countの乱数を生成 = ネズミがゴールするまでにかかった時間(ラップタイム) 11 rap_time_list = list()#リストとして初期化 12 for i in range(count): 13 rap_time_list.append(random.uniform(30,60))#30~60(秒)の乱数をリストに追加。 14 #rap_time_listをデータフレームにし、0列目にラップタイムを持つデータフレームを作成。 15 df1_df = pandas.DataFrame(rap_time_list) 16 #上記データフレームにレーサー番号をつけたいので、indexを付与。 17 df1_df = df1_df.reset_index() 18 #0列目のラップタイムをソートして数字の小さい順(ゴール早かった順)にソート。 19 df2_df = df1_df.sort_values(by=0) 20 #レーサー番号もindexとして追従してソートされているので、利用して順位を取る。 21 for i in range(count): 22 race_result = [df2_df.iat[i,0] for i in range(count)] 23 return race_result 24 25#####レースを任意回数分(race_times回)行って結果リストを作成する関数の定義##### 26def race_def(race_num): 27 if __name__ == '__main__': 28 race_times = 600 29 initial_num_list = list(range(race_times)) 30 with Pool(processes=4) as p_para1: 31 race_result_list = p_para1.map(func=try_def, iterable=initial_num_list) 32 return race_result_list 33 34#実行したいプログラム 35if __name__ == '__main__': 36 initial_num_list2 = list(range(6)) 37 with Pool(processes=6) as p_para2: 38 race_result_list_2 = p_para2.map(func=race_def, iterable=initial_num_list2) 39print(race_result_list_2) 40 41

調べたこと

並列演算コードの書き方など
入れ子構造で並列演算しているサイトを探したが見つからなかった。

補足情報(FW/ツールのバージョンなど)

環境:google cocolaboratory

プログラミング初めて1周間程度の知識しかないので、
すみませんが、わかりやすくお願いできましたら幸いです。

よろしくお願い致します。

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2021/03/13 11:34 編集

PCの調子が悪いのでイマイチ検証できていませんが、直感的に「ん?」という部分がいくつか見つかりました。 ・ try_timesがdef try_def(try_times)のなかで呼び出されてないです。 ・ with Poolはプロセスを複数のプロセスで請け負う処理ですので、普通は入れ子構造の中で呼び出す(複数回呼び出す)ことはしません。 ・ da1_dfとdf1_df は同じでしょうか?どちらかが定義されるより前に呼び出されています。 ・ sort_valuesはdataframeのものでしょうか?import pandas as pd とか?
hiroki91629

2021/03/13 23:28

ご連絡ありがとうございます。 ・try_def(trytimes)は何でもいいから引数を1つ入れるとdef~returnまで実行するというイメージで作成しております。このような使い方はまずかったでしょうか。 ・普通はしないのですか。。。他の方法、書き方などはございませんでしょうか。 ・誤:da1_df[1] = list(range(count)) 修正致します。 ・import pandas入れておきます。
退会済みユーザー

退会済みユーザー

2021/03/14 21:36

編集ありがとうございます。こちらでも動作を試してみますね。 > ・try_def(trytimes)は何でもいいから引数を1つ入れるとdef~returnまで実行するというイメージで作成しております。このような使い方はまずかったでしょうか。 バグとは少しずれた話で、動かす分には全く問題ありません。
guest

回答3

0

解決したソースコード

Python

1ソースコード 2import concurrent.futures 3import pandas 4import random 5from multiprocessing import Pool 6import concurrent 7 8 9def inner_concurrent(num: int): 10 count = 3#count:レーサーの数 11 #要素数:countの乱数を生成 = ネズミがゴールするまでにかかった時間(ラップタイム) 12 rap_time_list = list()#リストとして初期化 13 for i in range(count): 14 rap_time_list.append(random.uniform(30,60))#30~60(秒)の乱数 15 #rap_time_listをデータフレームにし、0列目にラップタイムを持つデータフレームを作成。 16 df1_df = pandas.DataFrame(rap_time_list) 17 #上記データフレームにレーサー番号をつけたいので、indexを付与。 18 df1_df = df1_df.reset_index() 19 #0列目のラップタイムをソートして数字の小さい順(ゴール早かった順)にソート。 20 df2_df = df1_df.sort_values(by=0) 21 #レーサー番号もindexとして追従してソートされているので、利用して順位を取る。 22 for i in range(count): 23 race_result = [df2_df.iat[i,0] for i in range(count)] 24 return race_result 25 26 27def outer_concurrent(): 28 with concurrent.futures.ProcessPoolExecutor(max_workers=4) as executor: 29 futures = [executor.submit(inner_concurrent, i) for i in range(600)] 30 return futures 31 32 33def main(): 34 with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor: 35 futures = [executor.submit(outer_concurrent) for _ in range(6)] 36 37 for outer_f in futures: 38 for inner_f in outer_f.result(): 39 print(f"result = {inner_f.result()}") 40 41 42if __name__ == "__main__": 43 main() 44

#皆様ありがとうございました。
こちらのコードで動きましたので、こちらの元となった記事をご紹介頂いた方をベストアンサーとしたいと思います。

素人の感想ですが、インナープロセス(入れ子の中)の方を「ProcessPoolExecutor」として、アウターのプロセス(メインの方)は「ThreadPoolExecutor」とすると、うまくいくようです。
逆にすると、元の記事にあったように、「TypeError: can't pickle _thread.RLock objects」と、エラーが出ます。

投稿2021/03/16 03:16

編集2021/03/16 03:24
hiroki91629

総合スコア3

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

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

退会済みユーザー

退会済みユーザー

2021/03/16 11:09

試さないと詳しいことは言えませんが、ProcessPoolとThreadPoolでハードウエアの中のリソースの割き具合が違うらしく、それに起因して得意な処理不得意な処理があるそうです(重い処理を少数、軽い処理を多数等)。あとは並列であるのはjoblibでしょうか。使いやすいものを使えばいいのかな?という気もします。
guest

0

ベストアンサー

まずは複雑な処理を抜いて動かすところと思います。

(以下シンプルなサンプル)

Python3

1import pandas 2import random 3from multiprocessing import Pool 4 5#####一様な乱数に従って任意回数思考した後、着順を返す関数の定義##### 6def try_def(try_times): 7 count = 3#count:レーサーの数 8 #要素数:countの乱数を生成 = ネズミがゴールするまでにかかった時間(ラップタイム) 9 # rap_time_list = [] 10 rap_time_list = list()# ※リストとして初期化 11 12 for i in range(count): 13 14 # rap_time_list = rap_time_list + [random.uniform(30,60)]#30~60(秒)の乱数 15 rap_time_list.append(random.uniform(30,60))#30~60(秒)の乱数 # ※リストに追加 16 17 #rap_time_listをデータフレームにし、0列目にラップタイムを持つデータフレームを作成。 18 # df1_df = rap_time_list 19 df1_df = pandas.DataFrame(rap_time_list) # ※pandasのDataFrameに格納させました。 20 21 22 #上記データフレームにレーサー番号をつけたいので、1列目に番号をつけてラップタイムと紐付ける。 23 # df1_df[1] = list(range(count)) 24 df1_df = df1_df.reset_index() #これでインデックスを付与 25 26 27 #0列目のラップタイムをソートして数字の小さい順(ゴール早かった順)にソート。 28 df2_df = df1_df.sort_values(by=0) 29 print(df2_df) 30 31 #レーサー番号も追従してソートされているので、利用して順位を取る。 32 #レーサー番号はdf2_dfの1列目に入っている。 33 for i in range(count) : 34 print("Ranking:",i+ 1,"Index:",df2_df.iat[i,0] ," Record:",df2_df.iat[i,1]) 35 36 race_result = [df2_df.iat[i,0] for i in range(count)] 37 38 return race_result 39 40import concurrent.futures 41 42#####レースを任意回数分(race_times回)行って結果リストを作成する関数の定義##### 43def race_def(race_num): 44 if __name__ == '__main__': 45 race_times = 600 46 initial_num_list = list(range(race_times)) 47 48 49 # ※multiprocessingをする前に、普通の状態でエラーがない状態にしたいため、 50 # まずはmultiprocessingを解除しました。 51 # with Pool(processes=4) as p_para1: 52 # race_result_list = p_para1.map(func=try_def,iterable=initial_num_list) 53 race_result_list = try_def(initial_num_list) 54 return race_result_list 55 56#実行したいプログラム 57if __name__ == '__main__': 58 initial_num_list2 = list(range(6)) 59 60 61 # ※multiprocessingをする前に、普通の状態でエラーがない状態にしたいため、 62 # まずはmultiprocessingを解除しました。 63 # with Pool(processes=6) as p_para2: 64 # race_result_list_2 = p_para2.map(func=race_def, iterable=initial_num_list2) 65 race_result_list_2 = race_def(initial_num_list2) 66 67print(race_result_list_2) 68

私のところではMPが動かせなかったので推定での答えですが、

下記コードが進行不可能な理由。

MPの中でMPを走らせたことが怪しい

下記コードを動かす改善方法。

上のシンプルな例を参照ください。

他の有効な並列演算方法はあるかどうか。

processpoolexecutorとthreadpoolexecutorでしょうか。たとえばここ
先の方の答えにもありますが、オーバーヘッドすると遅くなるので多用は禁物です。

daemonic processesとは何か。

親スレッドがいて、子スレッドがいます。子スレッドを「デーモン」扱いにすると、親スレッドが終了したときに子スレッドも道連れにして終了してくれるスレッドです。多分掲載のコードだと子スレッドが親スレッドになろうとしてエラーをはいているのではないか、と思います。(検証できていないため推測ですよ!)

投稿2021/03/15 13:49

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

hiroki91629

2021/03/16 01:34

ご回答ありがとうございます。 コード例もご丁寧にありがとうございます。 きちんと動きました。 (そのままコピペだと「race_result_list = try_def(initial_num_list)」の前にスペースが1個入っちゃうようでしたので、そこだけ修正すれば動きました) ところで、大変恐縮なのですが、並列処理で動かしたく存じます。 そちらもサンプルコードをお出し頂けましたらベストアンサーとしたいと存じます。 「processpoolexecutorとthreadpoolexecutorでしょうか。たとえばここ。」と、改善案を頂きましたので、こちら、自身で試行してみようと存じます。
guest

0

説明は以下です。

"AssertionError: daemonic processes are not allowed to have children"について

ただ、このように実行しても性能は上がらないでしょう。
並列処理は魔法ではありません。
あなたのPCのハードウェア性能、サーバがあなたに割り当ててくれるCPU資源の制限があります。
無駄にプロセスを増やすことは、プロセス生成と終了のオーバーヘッドを増やし、むしろ性能を悪化させます。

投稿2021/03/13 11:09

ppaul

総合スコア24670

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

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

hiroki91629

2021/03/13 23:38

ご回答、誠にありがとうございます。 追加の質問で恐縮ですが、添付URL中にAssertionErrorの無視ができるとありますが、調べてもよくわかりませんでした。ご解説頂けますと大変助かります。 性能が悪化しても良いので、何とか入れ子構造で並列処理できませんでしょうか。 もしくは、デーモンプロセスではない並列演算の方法などございましたらお教え頂けますと幸いです。 以上よろしくお願い致します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問