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

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

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

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

Q&A

解決済

1回答

5162閲覧

multiprocessingのrun()メソッドの挙動がわかりません

takey

総合スコア312

Python 3.x

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

1グッド

2クリップ

投稿2017/04/21 08:21

編集2017/04/21 12:00

###前提・実現したいこと
Python3.4でmultiprocessingモジュールを使ったマルチプロセスのプログラムを書いています。
multiprocessingのrun()メソッド内の挙動が、思った通りに動作してくれません。

###発生している問題
run()メソッド内でメンバ変数を書き換えても、反映されないように見えます。ソースコードを見てください。

###該当のソースコード

python

1import multiprocessing as mp 2import sys 3import time 4import os 5 6class TestProcess(mp.Process): 7 def __init__(self, v): 8 super(TestProcess, self).__init__() 9 self.value = v 10 self.queue = mp.Queue() 11 12 def set_value(self, v): 13 # メインプロセス側でvalueの値を設定するための関数 14 self.value = v 15 16 def value_into_queue(self): 17 # メインプロセス側でvalueをキューに入れるための関数 18 self.queue.put(self.value) 19 20 def run(self): 21 print("=== start sub process===") 22 self.value = -1 23 #self.queue.put(self.value) 24 25if __name__ == "__main__": 26 print("=== start main thread (main) ===") 27 p1 = TestProcess(0) 28 p1.start() 29 p1.join() 30 31 p1.value_into_queue() # p1のvalueをキューに入れる 32 print(p1.queue.get()) # p1のvalueを取り出す 33 time.sleep(1) 34 35 p1.set_value(100) # p1のvalueをセットする 36 p1.value_into_queue() # p1のvalueをキューに入れる 37 print(p1.queue.get()) # p1のvalueを取り出す 38 39 print("=== end main thread (main) ===") 40

run()メソッド内でself.value = -1をしているので最初に取り出される数値は-1になるはずです。しかし実行結果は次のようになりました。

=== start main thread (main) === === start sub process=== 0 100 === end main thread (main) ===

###試したこと
run()メソッド内を次のように書き換えたところ、意図するような動作にはなりました。

python

1 def run(self): 2 print("=== start sub process===") 3 self.value = -1 4 self.queue.put(self.value)

以下は結果です。最初に-1を取り出せています。

=== start main thread (main) === === start sub process=== -1 0 === end main thread (main) ===

なぜこのような違いが起きるのでしょうか?
なぜ最初のプログラムでは、-1を取り出せないのでしょうか?
よろしくお願いします。

###補足情報(言語/FW/ツール等のバージョンなど)
python3.4、OSはRaspbianです

toritoritorina👍を押しています

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

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

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

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

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

magichan

2017/04/21 09:46

修正前と修正後のコードが全く同じように見えます。多分、修正前のコードは "self.queue.put(self.value)" の部分の記述が無いのが正解かと思うのですが、それで間違いありませんか?
takey

2017/04/21 12:01

間違いありません。質問を修正しました。大変失礼しました。
guest

回答1

0

ベストアンサー

multiprocessing が プロセスベース の並列処理ということにご注意ください。

Process.start() から起動されたTestProcess.run() 上の処理は、『別プロセス(子プロセス)で実行』つまり『現在のメモリ空間とは別のメモリ空間上で実行』されます。
そのため別プロセス上でいくらクラスのメンバ変数を書き換えても、それは別メモリ空間上での変更であり、現在のメモリ空間での変更ではないため、現在のプロセスではメンバ変数の値は変わりません。

この点が(同じメモリ空間で動作する) スレッドベース とは大きく異なります。
スレッドベースのように変数やファンクションコールによるデータの受け渡しができませんので、プロセス間では今回使用しているキューパイプ共有メモリを使用してデータを受け渡す必要があります。

質問でのサンプルコードでは、現プロセスにてクラスの生成時にコンストラクタで__TestPrecess.value__に値(0)を入れるまでの処理を行っており、TestProcess.value の書き換え(-1)は別プロセス上の処理しております。
よってp1.join()後の(現プロセスでの)TestPrecess.value の値は0で問題ないかと思われます。

投稿2017/04/21 13:22

編集2017/04/21 13:55
magichan

総合スコア15898

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

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

takey

2017/04/24 00:30

ああ…ようやく理解できたような気がします。 run()関数はサブプロセスで動作しているから、run()関数内でself.value=-1をしても、メインプロセス側のself.valueはコンストラクタで代入されたself.value=0のままなのですね。 もっと言うと、set_value()でメインプロセス側からサブプロセスのメンバ変数self.valueを書き換えているつもりだったんですが、そんなことはできていないのですね。 self.queueのみがメインとサブで共有メモリ扱い(?)になっているということでしょうか。 ともあれ、納得しました。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問