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

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

ただいまの
回答率

91.44%

  • Python 3.x

    2208questions

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

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

解決済

回答 1

投稿 2017/04/21 17:21 ・編集 2017/04/21 21:00

  • 評価
  • クリップ 1
  • VIEW 313

takey

score 80

前提・実現したいこと

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

発生している問題

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

該当のソースコード

import multiprocessing as mp
import sys
import time
import os

class TestProcess(mp.Process):
    def __init__(self, v):
        super(TestProcess, self).__init__()
        self.value = v
        self.queue = mp.Queue()

    def set_value(self, v):
        # メインプロセス側でvalueの値を設定するための関数
        self.value = v

    def value_into_queue(self):
        # メインプロセス側でvalueをキューに入れるための関数
        self.queue.put(self.value)

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

if __name__ == "__main__":
    print("=== start main thread (main) ===")
    p1 = TestProcess(0)
    p1.start()
    p1.join()

    p1.value_into_queue()  # p1のvalueをキューに入れる
    print(p1.queue.get())  # p1のvalueを取り出す
    time.sleep(1)

    p1.set_value(100)      # p1のvalueをセットする
    p1.value_into_queue()  # p1のvalueをキューに入れる
    print(p1.queue.get())  # p1のvalueを取り出す

    print("=== end main thread (main) ===")


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

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

試したこと

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

    def run(self):
        print("=== start sub process===")
        self.value = -1
        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です

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

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

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

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • magichan

    2017/04/21 18:46

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

    キャンセル

  • takey

    2017/04/21 21:01

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

    キャンセル

回答 1

checkベストアンサー

+3

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

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

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

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

投稿 2017/04/21 22:22

編集 2017/04/21 22:55

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

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

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

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/04/24 09:30

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

    キャンセル

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

ただいまの回答率

91.44%

関連した質問

  • 解決済

    pythonのエラー

    testThreadが見つからないというメッセージが出てきたのですが、どこに問題があるのでしょうか? よろしくお願いします コード #-*- coding utf-8-*-

  • 解決済

    thread queueの最大数を設定して、その範囲で回す

    queueの最大数を2個として満杯の場合は待機、 空きができ次第queueを追加するような処理がしたいです。 from threading import Thread, a

  • 解決済

    [Flask] ボタンでスレッドの開始と終了をコントロールさせる方法

     やりたいこと フォーム入力でなにかしらwebサービスのログイン情報を登録。 登録した情報の一覧画面で、アカウント情報の横にはボタンがあって、 開始ボタンを押したら何かしらの

  • 解決済

    マルチスレッドマルチスレッドのサンプルファイルを作ったがエラーになる

    お世話になります マルチスレッドマルチスレッドのサンプルファイルを作ったがnameエラーになり,どこが間違っているのかを知りたいです。 # -*- coding: utf-

  • 解決済

    wxPythonにおいて、USBカメラの画像表示をしたい

    前提・実現したいこと ここ一週間くらい、teratailの皆様の力を借りながら、python上で動く動画や画像を表示できるGUIを作っています。画像は何とか表示でき、画像とパネル

  • 解決済

    Pythonのthreadingにおける、終了時の処理

    前提・実現したいこと Pythonを使って、動画や画像を表示するGUIを作っています。その中で、みなさまのご支援を頂ながらカメラの画像を取り込んで再生できるところまで来ました。

  • 解決済

    リストの情報を他のクラスに渡す

    前提・実現したいこと 随時更新されていくリストの情報を他のクラスに渡したい 発生している問題・エラーメッセージ 今現在三目並べのプログラムを作っていますが、盤の情報を se

  • 受付中

    Pythonで一定間隔の処理をする

    Python3.6.1を使っています。 したいこととしては、一秒間に一回関数を呼び出すということがしたいです。 以下の方法を試したのですがエラーがでて動きませんでした。 コードがお

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

  • Python 3.x

    2208questions

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