2012-06-27 21 views
7

Các chương trình sau đây:Tại sao tôi không thể sử dụng operator.itemgetter trong đa xử lý.Pool?

import multiprocessing,operator 
f = operator.itemgetter(0) 
# def f(*a): return operator.itemgetter(0)(*a) 
if __name__ == '__main__': 
    multiprocessing.Pool(1).map(f, ["ab"]) 

không thành công với các lỗi sau:

Process PoolWorker-1: 
Traceback (most recent call last): 
    File "/usr/lib/python3.2/multiprocessing/process.py", line 267, in _bootstrap 
    self.run() 
    File "/usr/lib/python3.2/multiprocessing/process.py", line 116, in run 
    self._target(*self._args, **self._kwargs) 
    File "/usr/lib/python3.2/multiprocessing/pool.py", line 102, in worker 
    task = get() 
    File "/usr/lib/python3.2/multiprocessing/queues.py", line 382, in get 
    return recv() 
TypeError: itemgetter expected 1 arguments, got 0 

Tại sao tôi nhận được lỗi (trên CPython 2.7 và 3.2 trên Linux x64), và tại sao nó biến mất nếu tôi bỏ ghi chú dòng thứ ba?

Trả lời

6

Vấn đề ở đây là các module đa qua đối tượng bằng cách sao chép vào các quá trình khác (rõ ràng), và các đối tượng itemgetter không copyable sử dụng bất kỳ phương tiện rõ ràng:

In [10]: a = operator.itemgetter(0) 
Out[10]: copy.copy(a) 
TypeError: itemgetter expected 1 arguments, got 0 

In [10]: a = operator.itemgetter(0) 
Out[10]: copy.deepcopy(a) 
TypeError: itemgetter expected 1 arguments, got 0 

In [10]: a = operator.itemgetter(0) 
Out[10]: pickle.dumps(a) 
TypeError: can't pickle itemgetter objects 

# etc. 

Vấn đề không phải là thậm chí cố gắng gọi f bên trong các quá trình khác; nó đang cố gắng sao chép nó ngay từ đầu. (Nếu bạn nhìn vào dấu vết ngăn xếp, mà tôi bỏ qua ở trên, bạn sẽ thấy nhiều thông tin hơn về lý do tại sao điều này không thành công.)

Tất nhiên điều này không quan trọng, vì nó gần như dễ dàng và hiệu quả để xây dựng một itemgetter mới trên bay như để sao chép một. Và đây là chức năng "f" thay thế của bạn. (Sao chép một chức năng tạo ra một itemgetter trên bay không yêu cầu sao chép một itemgetter, tất nhiên.)

Bạn có thể biến "f" thành một lambda. Hoặc viết một hàm tầm thường (tên hoặc lambda) thực hiện điều tương tự mà không cần sử dụng itemgetter. Hoặc viết một thay thế itemgetter đó là copyable (mà rõ ràng sẽ không được tất cả những khó khăn). Nhưng bạn không thể trực tiếp sử dụng các đối tượng itemgetter như-là cách bạn muốn.

+0

Ồ, tôi thực sự đã học được điều gì đó từ câu trả lời của bạn. 1 và cảm ơn bạn. – steveha

+1

Nhân tiện, trong trường hợp bạn đang băn khoăn, lý do thực sự tại sao itemgetter không thể được sao chép (và không thể so sánh, không thể được băm, không có repr hữu ích rõ ràng, vv) isn ' t nhiều đến mức bất cứ ai nghĩ rằng nó sẽ là một ý tưởng tồi để thực hiện tất cả điều đó trong operator.c, vì không ai nghĩ rằng nó đủ quan trọng để có giá trị thực hiện. Có một chuỗi python-dev hoặc python-ideas về nó ở đâu đó. – abarnert

+1

Lưu ý rằng nó không thành công với một lambda là tốt, nhưng với một hợp lý hơn 'PicklingError: Không thể chọn : tra cứu thuộc tính __builtin __. Function failed'. – phihag

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