Có một cách rút gọn khác mà bạn có thể sử dụng, mặc dù nó có thể không hiệu quả tùy thuộc vào những gì trong các thể hiện trong lớp của bạn.
Như mọi người đã nói vấn đề là multiprocessing
mã phải chọn những thứ mà nó gửi đến các quy trình con mà nó đã bắt đầu và bộ chọn không thực hiện các phương thức cá thể.
Tuy nhiên, thay vì gửi phương thức cá thể, bạn có thể gửi cá thể lớp thực tế, cộng với tên của hàm để gọi, đến một hàm thông thường sau đó sử dụng getattr
để gọi phương thức cá thể, do đó tạo ra phương thức ràng buộc trong quy Pool
trình con. Điều này tương tự với việc xác định một __call__
phương thức ngoại trừ việc bạn có thể gọi nhiều hơn một hàm thành viên.
Đánh cắp mã của @ EricH. Từ câu trả lời của anh ấy và chú thích nó một chút (tôi đã gõ lại do đó tất cả các tên thay đổi và vì vậy, vì một số lý do, điều này có vẻ dễ hơn cắt và dán :-)) để minh họa cho tất cả các phép thuật:
import multiprocessing
import os
def call_it(instance, name, args=(), kwargs=None):
"indirect caller for instance methods and multiprocessing"
if kwargs is None:
kwargs = {}
return getattr(instance, name)(*args, **kwargs)
class Klass(object):
def __init__(self, nobj, workers=multiprocessing.cpu_count()):
print "Constructor (in pid=%d)..." % os.getpid()
self.count = 1
pool = multiprocessing.Pool(processes = workers)
async_results = [pool.apply_async(call_it,
args = (self, 'process_obj', (i,))) for i in range(nobj)]
pool.close()
map(multiprocessing.pool.ApplyResult.wait, async_results)
lst_results = [r.get() for r in async_results]
print lst_results
def __del__(self):
self.count -= 1
print "... Destructor (in pid=%d) count=%d" % (os.getpid(), self.count)
def process_obj(self, index):
print "object %d" % index
return "results"
Klass(nobj=8, workers=3)
Kết quả đầu ra cho thấy, trên thực tế, hàm tạo được gọi một lần (trong pid gốc) và hàm hủy được gọi 9 lần (một lần cho mỗi bản sao được thực hiện = 2 hoặc 3 lần cho mỗi tiến trình pool-worker khi cần, cộng với một lần trong bản gốc quá trình). Điều này thường ổn, như trong trường hợp này, vì trình chọn mặc định tạo một bản sao của toàn bộ thể hiện và (bán) bí mật điền lại nó trong trường hợp này, thực hiện:
obj = object.__new__(Klass)
obj.__dict__.update({'count':1})
Tại sao mặc dù bộ hủy được gọi tám lần trong ba quy trình worker, nó đếm ngược từ 1 đến 0 mỗi lần, nhưng tất nhiên bạn vẫn có thể gặp rắc rối theo cách này. Nếu cần thiết, bạn có thể cung cấp của riêng bạn __setstate__
:
def __setstate__(self, adict):
self.count = adict['count']
trong trường hợp này chẳng hạn.
PicklingError: Can't pickle <class 'function'>: attribute lookup builtins.function failed