2016-07-07 9 views
7

WindowsとLinux(両方python2.7付き)、Windows上でmultiprocessing.Processは、グローバルオブジェクトと関数の引数

'''import_mock.py''' 
to_mock = None 
'''test.py''' 
import import_mock 
from multiprocessing import Process 

class A(object): 
    def __init__(self): 
     self.a = 1 
     self.b = 2 
     self.c = 3 

    def __getstate__(self): 
     print '__getstate__' 
     return { 'a': self.a, 'b': self.b, 
       'c':0 } 

def func(): 
    import_mock.to_mock = 1 
    a = A() 
    return a 

def func1(a): 
    print a.a, a.b, a.c 
    print import_mock.to_mock 


if __name__ == '__main__': 
    a = func() 
    p = Process(target=func1, args=(a,)) 
    p.start() 
    p.join() 

上で実行されている場合は、次のコードは、異なる出力を持っているため、WindowsおよびLinux上で異なる動作をする理由、出力は次のようになります。

に私が期待したもの

ある

__getstate__ 
1 2 0 
None 

それはグローバルオブジェクトと渡されたargをクローンしません。

私の質問は、彼らの行動が違う理由ですか?そして、LinuxコードをWindowsと同じように動作させる方法は?

+0

物事は2つのOSで異なって実装されているためです。 Windows上では、子プロセスがそれらを使用できるように、マルチプロセッシングの多くのタイプをpicklableにする必要があることがドキュメントに記載されています。その意味は、他のOSではそうである必要はないということです。 'multiprocessing'モジュールのドキュメントにログインする際の[このセクション](https://docs.python.org/2/library/multiprocessing.html#logging)は、あなたの特定の問題に役立つかもしれません。 – martineau

答えて

5

Windowsの場合、各プロセスは元のモジュールを「ゼロから」インポートしますが、Unix-yシステムではメインプロセスのみがモジュール全体を実行し、他のすべてのプロセスはその時点で存在するものを表示しますfork()新しいプロセスを作成するために使用されます(いいえ、)。内部では、multiprocessing内部では新しいプロセスを作成するたびに呼び出されます。で詳細に

は、import_mockあなた:import_mock.to_mockのUnix-yのプラットフォームで

  • 1に、メインプロセスはfunc()を呼び出し、設定され、それがどのようなすべての新しいプロセスのすべてのプラットフォームで

    • ですそれ以降はfork()が発生するので、1はすべての新しいプロセスが継承する状態です。

    • Windowsでは、すべての新しいプロセスがモジュール全体を「最初から」実行します。そこで彼らはそれぞれ独自の、新しいバージョンのimport_mockをインポートします。メインプロセスだけがfunc()を呼び出すため、メインプロセスのみがto_mockが1に変わるとみなします。その他のプロセスは新鮮なNone状態を参照してください。すべての期待だし、実際に簡単な

    はそれがmultiprocessing実装の詳細についての詳細は、依存しているため、aは微妙である渡すと何が起こっている二度目;-)

    を理解します。実装が最初からすべてのプラットフォームで引数を取り除くことを選択できましたが、そうではありませんでした。プラットフォーム上のものを壊すことなく変更するには遅すぎます。そのためコピー・オン・ライトfork()セマンティクスの

    は、Unix-yのシステム上でProcess()引数を酸洗する必要はないたので、実装がやったことはありません。しかし、fork()がなければ、Windows上でピクルする必要があります。

    "Windowsの実装"(spawn)をすべてのプラットフォームで実行できるようになる以前は、クロスプラットフォームの驚きを回避する機械的な方法はありません。

    しかし、実際には、私はめったにこれによって悩まされていません。 を知っていると、例えば、マルチプロセッシングは酸漬けに大きく依存することがあります。 A()インスタンスを渡す "問題"が発生した唯一の理由は、デフォルトの__getstate__()をオーバーライドすることで、pickleトリックをプレイしていることです。

  • 8

    Linux(および他のUnixライクなOS)では、Pythonのmultiprocessingモジュールでfork()を使用して、親プロセスのメモリ状態のコピーを効率的に継承する新しい子プロセスを作成します。これは、通訳者が、Processargsとして渡されたオブジェクトをピクルする必要がないことを意味します。これは、子プロセスが既に通常の形で利用できるようになるからです。

    Windowsではfork()システムコールがありません。したがって、multiprocessingモジュールは、子生成プロセスを動作させるためにもう少し作業を行う必要があります。 fork()ベースの実装が最初に行われ、フォークしていないWindowsの実装が後で行われました。

    Pythonの開発者は、Pythonを実行しているプラ​​ットフォームに基づいて子プロセスの作成方法が大きく異なることがあると誤解していることがよくありました。したがって、Python 3.4では、新しいシステムが追加され、select the start method that you would prefer to useになりました。オプションは"fork","forkserver"および"spawn"です。 "fork"メソッドは、Unixライクなシステムではデフォルトのままです(以前のバージョンのPythonでは唯一の実装でした)。 "spawn"メソッドは、Windowsではデフォルトの(そして唯一の)オプションですが、現在はUnixライクなシステムでも使用できます。 "forkserver"メソッドは、2つの間のハイブリッドの一種です(一部のUnixライクなシステムでのみ利用可能です)。ドキュメント内のメソッドの違いについては、さらに詳しく読むことができます。