2016-07-13 10 views
1

ファイルやグローバル変数を読み込むためのPythonマルチプロセスをテストしただけですが、何か不思議なことが起こります。 expampleため何か奇妙なことがPythonマルチプロセスで起こる

import multiprocessing 

a = 0 

def test(lock, name):  
    global a 
    with lock:   
     for i in range(10): 
      a = a + 1 
     print "in process %d : %d" % (name, a) 

def main():  
    lock = multiprocessing.Lock()    

    p1 = multiprocessing.Process(target=test, args=(lock, 1)) 
    p2 = multiprocessing.Process(target=test, args=(lock, 2)) 

    p1.start() 
    p2.start() 

    p1.join() 
    p2.join() 

    print "in main process : %d" % a 

if __name__=='__main__': 
    main() 

プログラムは、グローバル変数を読みますが、出力は次のようになります。

in process 1 : 10 
in process 2 : 10 
in main process : 0 

サブプロセスが適切にグローバル変数を取得し、編集することはできませんようです。また、プログラムを変更してファイルを読み込むと、各サブプロセスはファイルを完全に読み込み、ロックを無視します。

これはどのように起こりますか?そしてこの問題を解決するには?

+0

私はあなたがあなたがマルチスレッドの代わりに、同時実行のためのマルチプロセッシング使用する場合があります 'multiprocessing.Manager' – mgilson

+0

を使用してグローバル状態を管理する必要があるだろうと信じている:ここでは例です。すべてのスレッドは、単一のプロセスの一部です。 – VPfB

答えて

1

グローバル変数はプロセス間で共有されません。新しいProcess()を作成して起動すると、そのプロセスは現在のPythonインタプリタの別の "クローン"コピーで実行されます。 Process()内から変数を更新するだけで、それがで更新される特定のプロセスにローカル変数を更新します。

Pythonのプロセス間でデータを共有するために、我々はmultiprocessing.Pipe()multiprocessing.Queue()multiprocessing.Value()multiprocessing.Array()かのいずれかが必要他のマルチプロセッシングに安全なコンテナ。

ここにあなたのコードに基づく例です:私はあなたが本当にグローバル変数を使用したい場合は、あなたがmultiprocessing.Manager()を使用することができ、今

In process 1: 10 
In process 2: 20 
In main process: 20 

を、しかし:

import multiprocessing 

def worker(lock, counter, name): 
    with lock:   
     for i in range(10): 
      counter.value += 1 

     print "In process {}: {}".format(name, counter.value) 

def main(): 
    lock = multiprocessing.Lock()  
    counter = multiprocessing.Value('i', 0)   

    p1 = multiprocessing.Process(target=worker, args=(lock, counter, 1)) 
    p2 = multiprocessing.Process(target=worker, args=(lock, counter, 2)) 

    p1.start() 
    p2.start() 

    p1.join() 
    p2.join() 

    print "In main process: {}".format(counter.value) 

if __name__=='__main__': 
    main() 

これは私に与えます最初の方法が望ましいと思っています。これは "重い"解決策です。

import multiprocessing 

manager = multiprocessing.Manager() 
counter = manager.Value('i', 0); 

def worker(lock, name): 
    global counter 

    with lock:   
     for i in range(10): 
      counter.value += 1 

     print "In process {}: {}".format(name, counter.value) 

def main(): 
    global counter 

    lock = multiprocessing.Lock()  

    p1 = multiprocessing.Process(target=worker, args=(lock, 1)) 
    p2 = multiprocessing.Process(target=worker, args=(lock, 2)) 

    p1.start() 
    p2.start() 

    p1.join() 
    p2.join() 

    print "In main process: {}".format(counter.value) 

if __name__=='__main__': 
    main() 
関連する問題