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

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

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

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

Python

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

Q&A

解決済

1回答

1578閲覧

Python3.8.4の並列処理のプロセス間で、クラスを共有したい

GUWAGUWA

総合スコア20

Python 3.x

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

Python

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

0グッド

1クリップ

投稿2020/07/25 04:00

編集2020/07/25 05:38

前提・実現したいこと

  • ファイル「asd.py」で「class dsa」を用意
  • 1つ目のプロセスで、一定間隔で「dsa.a」の値を変更(task関数)
  • 2つ目のプロセスファイル「dsa.a」の値を利用(printing関数)。

ですが、両方どうすれば、共有できるのでしょうか?

※同時アクセスによるデータ整合性は無視する。

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

console

1task = 1 2printing = 0 3printing = 0 4task = 2 5printing = 0 6printing = 0 7printing = 0 8task = 3 9printing = 0 10printing = 0 11printing = 0 12task = 4 13printing = 0 14printing = 0 15printing = 0

該当のソースコード

py

1#main.py 2import concurrent.futures as confu 3import time 4import asd 5 6# クラス変数出力 7def printing(): 8 while(1): 9 time.sleep(1) 10 print("printing = ", asd.dsa.a) 11 12# クラス変数変更 13def task(): 14 asd.dsa.a += 1 15 print("task = ",asd.dsa.a) 16 17 18def main(): 19 # - - - - 処理開始 - - - - # 20 with confu.ProcessPoolExecutor(max_workers=2) as executor: 21 executor.submit(printing) 22 for i in range(50): 23 executor.submit(task) 24 time.sleep(3) 25 26 # - - - - 並列処理が終わった後 - - - - # 27 # print(asd.dsa.a) 28 29if __name__ == '__main__': 30 main()

py

1# asd.py 2class dsa: 3 a = 0

試したこと

multiprocessingのValueにClassを入れる。
= 当然エラー

追記

「= 当然エラー」とはどんなコードを書いてどんなエラーが出たのでしょうか?

以下のとおり(main.py)です。なぜ、第一引数を「i」にしてるかは、適当に選んだからです。
第一引数の候補は、「sharedctypes.py」に存在する「typecode_to_type」の中から選ぶものです。(間違っていたらごめんなさい。)
その中にClassの引数が存在しなかったので、当然エラーと書きました。

py

1#main.py 2dsa = Value('i', asd.dsa)

console

1TypeError: an integer is required

py

1#sharedctypes.py 2typecode_to_type = { 3 'c': ctypes.c_char, 'u': ctypes.c_wchar, 4 'b': ctypes.c_byte, 'B': ctypes.c_ubyte, 5 'h': ctypes.c_short, 'H': ctypes.c_ushort, 6 'i': ctypes.c_int, 'I': ctypes.c_uint, 7 'l': ctypes.c_long, 'L': ctypes.c_ulong, 8 'q': ctypes.c_longlong, 'Q': ctypes.c_ulonglong, 9 'f': ctypes.c_float, 'd': ctypes.c_double 10 } 11```c

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

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

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

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

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

meg_

2020/07/25 04:17

「= 当然エラー」とはどんなコードを書いてどんなエラーが出たのでしょうか?
GUWAGUWA

2020/07/25 05:39

追記しました。
quickquip

2020/07/25 16:30

なんとなくXY問題 https://ja.meta.stackoverflow.com/questions/2701/ っぽい雰囲気が感じられて気になります。 なぜそんなことをしたいのか? が明らかになっていないせいで、解決したいことに対して間違ったアプローチをしようとしているのでは? という感じが拭えません。
GUWAGUWA

2020/07/26 02:12

XY問題については、初めて知りました。 確かに、XY問題問題が発生してますね! 質問する際に、処理を書かずに質問するのは、失礼かな?と考えてたので、付け焼き刃な知識で、処理を書くのがだめでした! これから質問する際はXY問題もよく考えて質問します!ありがとうございました!
guest

回答1

0

ベストアンサー

プロセス間で変数を共有するためには

  • mp.Value()はProcessPoolExecutor()よりも前に作成する
  • 引数initargsで共有メモリとして使用する変数を与える
  • 共有メモリとして使用する変数は引数initializerで呼ばれる関数内でグローバル変数に複製する

とします。これを踏まえた上で、(少しトリッキーですが)以下のようにするのはどうでしょう?

python

1# asd.py 2import multiprocessing as mp 3 4class dsa: 5 a = mp.Value("i", 0) 6

python

1# main.py 2import concurrent.futures as confu 3import time 4import asd 5 6 7# クラス変数出力 8def printing(): 9 while 1: 10 time.sleep(1) 11 with asd.dsa.a.get_lock(): 12 print("printing = ", asd.dsa.a.value) 13 14 15# クラス変数変更 16def task(): 17 with asd.dsa.a.get_lock(): 18 asd.dsa.a.value += 1 19 print("task = ", asd.dsa.a.value) 20 21 22def initializer(x): 23 asd.dsa.a = x 24 25 26def main(): 27 # - - - - 処理開始 - - - - # 28 with confu.ProcessPoolExecutor( 29 initializer=initializer, initargs=(asd.dsa.a,), max_workers=2 30 ) as executor: 31 executor.submit(printing) 32 for i in range(50): 33 executor.submit(task) 34 time.sleep(3) 35 36 # - - - - 並列処理が終わった後 - - - - # 37 # print(asd.dsa.a) 38 39 40if __name__ == "__main__": 41 main() 42

投稿2020/07/25 07:07

yymmt

総合スコア1615

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

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

GUWAGUWA

2020/07/25 11:02

回答ありがとうございます!2点ほど質問します。 1)これは、taskに入るたびにinitializer関数によって、グローバルなasd.dsa.aの内容が変わっているという解釈であっていますか? 2)今回のような内容をPythonでするには、これが最適なのでしょうか?もう少し分かりやすく実装できるモジュールなどはないのでしょうか?
yymmt

2020/07/25 12:13

1) いいえ、最初にサブプロセスx2回呼ばれるのみです。taskに入るたびに呼ばれることはありません。グローバルなasd.dsa.aの内容をinitializer()で上書きして変えているのはその通りです。 2) クラス変数をプロセス間で共有するというのがトリッキーになっている原因の1つですので普通のグローバル変数に頼れば多少分かりやすいと思います。またマルチプロセスにしているのは何か理由がありますか?マルチスレッドであればもう少し分かりやすいと思われます。
GUWAGUWA

2020/07/25 14:07

・クラス変数をプロセス間で共有するというのがトリッキーになっている原因の1つですので普通のグローバル変数に頼れば多少分かりやすいと思います。 >なるほど!私は複数個の変数を一気に共有しようと考えてます。ですので、クラスを用いようとしました。 ・またマルチプロセスにしているのは何か理由がありますか? >マルチプロセスにしている理由は、マルチスレッドよりも処理が軽いとサイトで見たからです。 最終的には画像処理ライブラリのOpenCVを用いようと考えてますので、処理が軽い法が良いのではと考え、マルチプロセスを利用しようと考えました。
yymmt

2020/07/25 14:58

高速化のためにマルチプロセスを使うのは正しい選択のような気がします。ただ今回のような実装だと、せっかくスレッドとプロセスの抽象化を図ったconcurrent.futuresを使うメリットがなくなってしまうので、(共通化された)分かりやすい方法を求めるのは共感するところです(デコレータをつければ共有メモリに乗るみたいな)。 ソースコードの共通化という意味ではMessagePackやgRPC+ProtocolBuffersなどでも良いですが、速度を重視しているので流石に共有メモリの方が早そうな気がします(試していませんので憶測です)。
GUWAGUWA

2020/07/28 06:58

MessagePackを行ってみましたが、書き込みと読み込みが発生するので、遅かったですね。 grpcはMessagePackよりも早かったので、そちらを利用します。ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問