Pythonについて学習します Multiprocessing ( PMOTWの記事 から)join()
メソッドが正確に何をしているのかを明確にしたいと思います。
2008年の古いチュートリアル では、以下のコードでp.join()
呼び出しがなければ、「子プロセスはアイドル状態になり、終了せず、手動で殺す必要があるゾンビになります」と述べています。
from multiprocessing import Process
def say_hello(name='world'):
print "Hello, %s" % name
p = Process(target=say_hello)
p.start()
p.join()
テストするためにPID
とtime.sleep
のプリントアウトを追加しましたが、わかる限り、プロセスは自動的に終了します。
from multiprocessing import Process
import sys
import time
def say_hello(name='world'):
print "Hello, %s" % name
print 'Starting:', p.name, p.pid
sys.stdout.flush()
print 'Exiting :', p.name, p.pid
sys.stdout.flush()
time.sleep(20)
p = Process(target=say_hello)
p.start()
# no p.join()
20秒以内:
936 ttys000 0:00.05 /Library/Frameworks/Python.framework/Versions/2.7/Reso
938 ttys000 0:00.00 /Library/Frameworks/Python.framework/Versions/2.7/Reso
947 ttys001 0:00.13 -bash
20秒後:
947 ttys001 0:00.13 -bash
動作は、p.join()
がファイルの最後に追加された場合と同じです。 Python今週のモジュールでは、 モジュールの非常に読みやすい説明 ;を提供しています。 「プロセスが処理を完了して終了するまで待つには、join()メソッドを使用します。」とはいえ、少なくともOS Xはそれを行っていたようです。
メソッドの名前についても疑問に思っています。 .join()
メソッドはここで何かを連結していますか?プロセスを終了と連結していますか?または、Pythonのネイティブ.join()
メソッドと名前を共有するだけですか?
join()
メソッドは、threading
またはmultiprocessing
とともに使用される場合、str.join()
とは関係ありません。実際には、何かを連結することはありません。むしろ、「この[スレッド/プロセス]が完了するのを待つ」という意味です。 join
モジュールのAPIはmultiprocessing
モジュールのAPIに似ているため、threading
モジュールはthreading
オブジェクトにjoin
を使用するため、Thread
という名前が使用されます。 「スレッドが完了するのを待つ」という意味のjoin
という用語の使用は、多くのプログラミング言語で一般的であるため、Pythonも同様に採用しました。
ここで、join()
の呼び出しの有無にかかわらず20秒の遅延が発生する理由は、デフォルトでは、メインプロセスが終了する準備ができたときに、実行中のすべてのmultiprocessing.Process
インスタンスで暗黙的にjoin()
を呼び出すためです。これは、multiprocessing
docsに明確に記載されているはずではありませんが、 プログラミングガイドライン セクションで言及されています。
また、非デーモンプロセスは自動的に結合されることに注意してください。
プロセスを開始する前に、daemon
のProcess
フラグをTrue
に設定することにより、この動作をオーバーライドできます。
p = Process(target=say_hello)
p.daemon = True
p.start()
# Both parent and child will exit here, since the main process has completed.
その場合、子プロセス メインプロセスが完了するとすぐに終了します :
デーモン
プロセスのデーモンフラグ、ブール値。これは、start()を呼び出す前に設定する必要があります。
初期値は作成プロセスから継承されます。
プロセスが終了すると、すべてのデーモンの子プロセスを終了しようとします。
join()
がない場合、メインプロセスは子プロセスが完了する前に完了できます。どのような状況でそれがゾンビにつながるかはわかりません。
join()
の主な目的は、メインプロセスが子プロセスの作業に依存する処理を行う前に、子プロセスが完了していることを確認することです。
join()
の語源は、fork
の反対です。これは、子プロセスを作成するためのUnixファミリオペレーティングシステムで一般的な用語です。単一のプロセスが複数に「分岐」し、「結合」して1つに戻ります。
join
が何をするのかを詳しく説明するつもりはありませんが、その背後にある語源と直観があります。
アイデアは、「 forks 」を実行して、そのうちの1つをマスター、残りのワーカー(または「スレーブ」)にするプロセスです。ワーカーが完了すると、マスターが「結合」され、シリアル実行が再開されます。
join
メソッドにより、マスタープロセスはワーカーが参加するのを待ちます。このメソッドは、それがマスターで発生する実際の動作であるため、「待機」と呼ばれる可能性があります(POSIXスレッドでは「結合」とも呼ばれますが、それはPOSIXで呼び出されます)。結合は、スレッドが適切に連携する結果としてのみ発生します。これは、マスターが行うものではありませんdoes。
「fork」および「join」という名前は、マルチプロセッシングでこの意味で使用されています 1963年以降 。
join()
は、ワーカープロセスが終了するのを待つために使用されます。 close()
を使用する前に、terminate()
またはjoin()
を呼び出す必要があります。
@Russellが言及したようにjoinはfork(Spawnsサブプロセス)の反対のようなものです。
結合を実行するには、close()
を実行する必要があります。これにより、それ以上のタスクがプールに送信されなくなり、すべてのタスクが完了すると終了します。または、terminate()
を実行すると、すべてのワーカープロセスがすぐに停止して終了します。
"the child process will sit idle and not terminate, becoming a zombie you must manually kill"
これは、メイン(親)プロセスは終了しますが、子プロセスはまだ実行中であり、完了したら、終了ステータスを返す親プロセスがありません。