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

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

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

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

Q&A

1回答

1324閲覧

PythonでMultiprocessing利用時にinputによる不具合

namuyan

総合スコア76

Python 3.x

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

1グッド

3クリップ

投稿2018/04/10 14:44

編集2022/01/12 10:55

Python3.5 Windows10 64bit
Multiprocessingモジュールを用いたプログラムを書いています。
ユーザーからのコマンド入力をinput()で受け付けていますがMultiprocessingと相性が悪く不具合を起こします。

問題をわかりやすくしたコードを下記に書きました。

python

1from multiprocessing import Process 2import time 3 4 5def hello(message): 6 while True: 7 time.sleep(1) 8 print(message) 9 10 11def work(): 12 print("start") 13 Process(target=hello, args=('nice.',)).start() 14 while True: 15 w = input(">> ") 16 print(w) 17 18if __name__ == '__main__': 19 work()

上記のプログラムを実行すると下記のようにプロセスが遅れて実行されます。
入力しなければ永遠に止まったままです。

commandline

1start 2>> a 3a 4>> c 5c 6>> nice. 7nice. 8nice.

input()以外でユーザーから入力を受け付ける必要があります。
何か良い方法はありませんでしょうか?

追記

これは"input()があるとMultiprocessingが始まらない"というPython自体のバグだと思います。
以下のような出力を想定しています。入力が無くてもループが始まるのが想定です。Linuxだとこういう動きになりました。

commandline

1start 2>> nice. 3nice. 4nice. 5nice.

inoutのBlockingがMultiprocessingをBlockして始まりません。
入力すると始まるという事からそう予想しています。
このinputはDebugする為に使用しています、任意の関数をexecで実行させたり変数を表示させたりなど。この手段が使えないと不便ですので解決したいです。

LouiS0616👍を押しています

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

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

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

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

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

tachikoma

2018/04/10 22:41

input()で何が問題になっているかもう少し説明して見てもらえませんか。入力と出力が混ざってしまうことが問題?
namuyan

2018/04/11 11:44

追記しました、宜しくお願いします。
tachikoma

2018/04/11 12:00

inputは標準入力を待っており、その後にサブプロセスを走らせるようにコードが書かれているので、言語のバグではないですね。プログラムは書かれた通りに動いています。お示しのログはサブプロセスの終了を待ってから次の入力を受け付けたいように見えますが(joinを使う場合に相当)
namuyan

2018/04/11 12:08

すみません、例が悪かったです。環境を書かなかったのも申し訳ありません。Processの場所を変更して追記しました。
umyu

2018/04/11 12:54

inputのブロックで暗黙的にプロセスが切り替わるのを期待しているコードに見えますが。おまじないでよければ、time.sleep(1)をProcess#startした後に。
namuyan

2018/04/11 13:44

Sleep入れると想定通りの動きになりますね。うむむ....何が起きているのかよくわからない。
guest

回答1

0

追記:
コメント欄でのやりとで本回答は質問者さんの課題ではないことがわかりましたので元の回答は取り消します。ついでに書いてしまって申し訳ないのですが、現象をはっきりさせるため次のようなコードにしてみてはいかがでしょうか?目的はinput()が完了した時刻とサブプロセスでprintする直前の時刻がはっきり分かるようにするためです。

xx.py

python

1from multiprocessing import Process 2import time 3 4st = time.time() 5 6def now(): 7 return f'{time.time() - st:.2f}' 8 9def hello(message, st_): 10 global st 11 st = st_ 12 time.sleep(2) 13 print(now(), message) 14 15def work(): 16 print(now(), "start") 17 while True: 18 w = input(">> ") 19 print(now(), w) 20 Process(target=hello, args=('nice.'+w, st)).start() 21 22if __name__ == '__main__': 23 work()

なお、開始時刻(st)をわざわざサブプロセスへ渡している理由は一応windowsとlinuxでnow()の結果の意味合いを同じにするためです。windowsですとspawnのためグローバル変数stは親プロセスの値がそのまま引き継がれますが、linuxですとfork&execのためかグローバル変数stが子供プロセス開始時に再設定されるようです。

上記プログラムをpython xx.pyとして動かしたときの実行結果は次のようになりました。

0.00 start >> a 3.30 a >> b 3.84 b >> c 4.43 c >> 5.41 nice.a 5.94 nice.b 6.54 nice.c d 20.57 d >> e 21.30 e >> 22.67 nice.d 23.41 nice.e

(Windows10 64bit, cpython 3.6.0, cmd.exeから)

元の回答

上記のプログラムを実行すると下記のようにプロセスが遅れて実行されます。

どういう動作を期待しているか今一つ確信がありませんが、もし「メインプロセスでのinput()による入力後、サブプロセスが完了するまで待ってから次のプロンプト表示&input()による入力を行いたい」ということなら、次のようにしてサブプロセスの完了を待てばよいです。

Python

1def work(): 2 print("start") 3 while True: 4 w = input(">> ") 5 print(w) 6 p = Process(target=hello, args=('nice.'+w,)) 7 p.start() 8 p.join() # <==これ

投稿2018/04/10 15:05

編集2018/04/11 14:18
KSwordOfHaste

総合スコア18392

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

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

namuyan

2018/04/11 11:48

予定ではMultiprocessingは非同期で動きますのでJoinでBlockするわけではありません。 このコードが問題なのはinputによりサブプロセスがBlockされて始まらない事です。 追記しましたのでよろしくお願いします。
KSwordOfHaste

2018/04/11 11:55

うーん・・・やはりそこなのですか。 自分には質問者さんが勘違いしているように思えます。 input()によりサブプロセスがblockされるのではなく、このプログラムがinput()後にサブプロセスを起動するように書かれているからサブプロセスが始まらないと考えるべきと思います。
KSwordOfHaste

2018/04/11 12:05

む・・・一応pythonを動かしている環境を伺った方がいいかもしれません。自分はubuntuのterminalやwindowsのコマンドプロンプトから動かしています。何かのIDEのコンソールからは動かしてみてません。ひょっとするとコンソールの種類によって動作が異なるかも(Multiprocessingの動きではなくコンソールの動作が違うという意味)
namuyan

2018/04/11 12:11

環境が重要でした。申し訳ありません、追記しました。 Windowsでは駄目ですがLinuxでは動きました。
tachikoma

2018/04/11 12:19

printのflushをtrueにしても変わりませんかね。
namuyan

2018/04/11 12:25

2つに入れましたが変わりません。Multiprocessingは難しいですね。
tachikoma

2018/04/11 12:28

ふーむ、なるほど。
KSwordOfHaste

2018/04/11 12:30 編集

windowsのコマンドプロンプトからもpowershellでも期待どうり動くような気がするのですが・・・Windows 10です。(ついでですが、cygwin64のterminalでも動きました)
tachikoma

2018/04/11 12:39

Windows環境では制約が多いのは知っていますが、これは困りますね。ほとんど興味に基づくものなのですが、multiprocessingをmultithreadingに切り替えるとどうなります?
namuyan

2018/04/11 12:44

コマンドラインに直接打ち込み実行すると"Can't get attribute 'hello' on <module '__main__' (built-in)>" と出て実行できません。pyファイルに書き込んで実行することを想定していますが、pyファイルからではどうでしょうか? threadingでは問題ありません。ちなみにsys.stdin.readline()でもBlockされますね。
tachikoma

2018/04/11 12:50

Windowsのmultiprocessingはif __name__==“__main__”:の後にしか実行できないですね。
KSwordOfHaste

2018/04/11 13:05

Process起動の種類のデフォルトがwindows=spawn、linux=forkという点に関係があるんでしょうかね。ファイルディスクリプターが共有されるかどうかといったあたりに影響がでると思うのですが。
can110

2018/04/11 13:23

横レス失礼します。 >ファイルディスクリプターが共有されるかどうか このfdはprint先の標準出力のことですかね? わたしもこの部分が気になってhelloでの出力先をprintではなく都度開く通常のファイル出力におきかえてみたのですが、結果は同じなんですよね。(main側のinputで入力完了されるまでファイル出力されない) なぜなんだろう?
KSwordOfHaste

2018/04/11 13:45

うーむ、難してついていけてません>< そもそも自分はwindowsで質問者さんがおっしゃる動作が再現できてさえいません。 コマンドプロンプトからpython xx.pyとやると動くように見えます。 cpython 3.6.0(いわゆるフツーのpython)なのですが、みなさん再現できてるのですよね?
tachikoma

2018/04/11 13:53

私まだ再現出来てないです。手元mac環境ゆえ…
can110

2018/04/11 13:54

こちらWin10+Anaconda(3.5.x)+コマンドプロンプト上(>python hoge.py)で再現したのですが どうにも理屈が分かりません^^; 明日以降、頭冷やして考えてみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.51%

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

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

質問する

関連した質問