2014-08-28 17 views
25

Tôi đang cố gắng sử dụng một hàm một phần để pool.map() có thể nhắm mục tiêu một hàm có nhiều tham số (trong trường hợp này là đối tượng Lock()).Python chia sẻ khóa giữa các quá trình

Dưới đây là ví dụ mã (lấy từ một câu trả lời cho một câu hỏi trước của tôi):

from functools import partial 

def target(lock, iterable_item): 
    for item in items: 
     # Do cool stuff 
     if (... some condition here ...): 
      lock.acquire() 
      # Write to stdout or logfile, etc. 
      lock.release() 

def main(): 
    iterable = [1, 2, 3, 4, 5] 
    pool = multiprocessing.Pool() 
    l = multiprocessing.Lock() 
    func = partial(target, l) 
    pool.map(func, iterable) 
    pool.close() 
    pool.join() 

Tuy nhiên khi tôi chạy mã này, tôi nhận được lỗi:

Runtime Error: Lock objects should only be shared between processes through inheritance. 

Tôi gì mất tích ở đây? Làm thế nào tôi có thể chia sẻ khóa giữa các quy trình con của tôi?

+0

Có một câu hỏi khác về cùng một vấn đề này, mặc dù lỗi cụ thể của chúng khác nhau - [Sự cố khi sử dụng khóa đa xử lý.Pool: lỗi tẩy] [http://stackoverflow.com/questions/17960296/trouble-using-a- lock-with-multiprocessing-pool-pickling-error) –

Trả lời

46

Xin lỗi, tôi đã nhận được điều này trong câu trả lời của tôi cho câu hỏi khác của bạn. Bạn không thể chuyển các đối tượng thông thường multiprocessing.Lock cho các phương thức Pool vì chúng không thể được chọn. Có hai cách để giải quyết vấn đề này. Một là để tạo ra Manager() và vượt qua một Manager.Lock():

def main(): 
    iterable = [1, 2, 3, 4, 5] 
    pool = multiprocessing.Pool() 
    m = multiprocessing.Manager() 
    l = m.Lock() 
    func = partial(target, l) 
    pool.map(func, iterable) 
    pool.close() 
    pool.join() 

Đây là một chút nặng chút, mặc dù; sử dụng một số Manager yêu cầu sinh sản quy trình khác để lưu trữ máy chủ Manager. Và tất cả các cuộc gọi đến acquire/release khóa phải được gửi đến máy chủ đó qua IPC.

Tùy chọn khác là chuyển số multiprocessing.Lock() thông thường lúc tạo hồ bơi, sử dụng số initializer kwarg. Điều này sẽ làm ví dụ khóa của bạn toàn cầu trong tất cả các lao động trẻ em:

def target(iterable_item): 
    for item in items: 
     # Do cool stuff 
     if (... some condition here ...): 
      lock.acquire() 
      # Write to stdout or logfile, etc. 
      lock.release() 
def init(l): 
    global lock 
    lock = l 

def main(): 
    iterable = [1, 2, 3, 4, 5] 
    l = multiprocessing.Lock() 
    pool = multiprocessing.Pool(initializer=init, initargs=(l,)) 
    pool.map(target, iterable) 
    pool.close() 
    pool.join() 

Giải pháp thứ hai có tác dụng phụ của không còn đòi hỏi partial.

+0

Cảm ơn bạn một lần nữa, thưa bạn. Điều này trông giống như những gì tôi cần. Thực sự đánh giá cao sự giúp đỡ liên tục! Các tùy chọn khác nhìn siêu tham gia. Tôi sẽ đi với chức năng khởi tạo để chia sẻ Khóa toàn cầu. – DJMcCarthy12

+0

Điều này làm việc tuyệt vời. Tôi cũng đặt một 'Queue' vào init để lưu nó trong mỗi cuộc gọi. – fantabolous

+1

@ dano cảm ơn rất nhiều câu trả lời của bạn, tôi cũng có cùng một truy vấn và giải pháp này hoàn toàn, tuy nhiên tôi có một truy vấn khác là tại sao phương pháp này không được sử dụng thường xuyên để chia sẻ trạng thái giữa các quá trình thay vì thực hiện có chi phí riêng để chạy một quy trình máy chủ và truy cập proxy? – bawejakunal

Các vấn đề liên quan