2017-07-27 14 views
1

SyncManager.Lockを正しく使用することに問題があります。私はofficial docを読んでいますが、実際の例はありません。 SyncManager.Eventを正しく使う方法もわかりません。SyncManager.LockまたはEventを正しく使用する方法は?

以下は、私の問題を説明するための最小限のコードです。 client1client2は共に共有オブジェクトStructを更新する必要があります。しかし、最初にclient1にロックを取得し、Structを更新してから、制御をclient2に渡します。現状のままでコードを実行すると、printステートメントはすべて混在します。

import multiprocessing as mp 
from multiprocessing.managers import SyncManager 
import time 

class Struct: 
    def __init__(self): 
     self.a = [] 

    def update(self, x, y): 
     self.a.append(x ** 2) 

    def get(self): 
     return self.a 

class Server(SyncManager): 
    pass 

global_S = Struct() 
Server.register('Struct', lambda: global_S) 

def server_run(): 
    print('Server starting ...') 
    manager = Server(('localhost', 8080), authkey=b'none') 
    manager.get_server().serve_forever() 


def client_run(name, x, y, wait): 
    server_proc = Server(('localhost', 8080), authkey=b'none') 
    server_proc.connect() 
    S = server_proc.Struct() 
    with server_proc.Lock(): 
     for i in range(5): 
      S.update(x+i, y+i) 
      print(name, S.get()) 
      time.sleep(wait) 


server = mp.Process(target=server_run) 
server.daemon = True 

client1 = mp.Process(target=client_run, args=('c1', 3,7, 1)) 
client2 = mp.Process(target=client_run, args=('c2', 100,120, .6)) 

server.start() 
time.sleep(0.3) # wait for server to spawn up 
client1.start() 
time.sleep(0.3) 
client2.start() 

client1.join() 
client2.join() 

出力例:

Server starting ... 
c1 [9] 
c2 [9, 10000] 
c2 [9, 10000, 10201] 
c1 [9, 10000, 10201, 16] 
c2 [9, 10000, 10201, 16, 10404] 
c1 [9, 10000, 10201, 16, 10404, 25] 
c2 [9, 10000, 10201, 16, 10404, 25, 10609] 
c2 [9, 10000, 10201, 16, 10404, 25, 10609, 10816] 
c1 [9, 10000, 10201, 16, 10404, 25, 10609, 10816, 36] 
c1 [9, 10000, 10201, 16, 10404, 25, 10609, 10816, 36, 49] 

答えて

1

私は回避策を考え出しました。

  1. これは、共有する代わりに常に新しいLockオブジェクトを作成しています。次の理由により、組み込みのSyncManager.Lock()を使用しないでください。
  2. threading.Lock()、NOT multiprocess.Lock()をラップします。マルチプロセッシングではうまくいかないようですね!

ソリューションは独自のロックマネージャを登録することである。

from multiprocessing.managers import BaseManager, AcquirerProxy 
global_lock = mp.Lock() 

def get_lock(): 
    print('getting global_lock') 
    return global_lock 

Server.register('Lock', get_lock, AcquirerProxy) 
関連する問題