Tôi nghĩ điều này là do quirk trong cách Người quản lý được triển khai.
Nếu bạn tạo ra hai đối tượng Manager.list, và sau đó thêm một trong những danh sách này để người kia, các loại danh sách mà bạn gắn những thay đổi bên trong danh sách phụ huynh:
>>> type(l)
<class 'multiprocessing.managers.ListProxy'>
>>> type(z)
<class 'multiprocessing.managers.ListProxy'>
>>> l.append(z)
>>> type(l[0])
<class 'list'> # Not a ListProxy anymore
l[0]
và z
không cùng một đối tượng và không hoạt động hoàn toàn theo cách bạn mong muốn như sau:
>>> l[0].append("hi")
>>> print(z)
[]
>>> z.append("hi again")
>>> print(l[0])
['hi again']
Như bạn có thể thấy, việc thay đổi danh sách lồng nhau không ảnh hưởng đến đối tượng ListProxy, nhưng thay đổi Đối tượng ListProxy thay đổi các nes ted danh sách. Các tài liệu thực sự explicitly notes this:
Note
Sửa đổi các giá trị có thể thay đổi hoặc các mục trong dict và danh sách các proxy sẽ không được tuyên truyền thông qua người quản lý, bởi vì proxy không có cách nào biết khi nào giá trị hoặc các mục của nó được sửa đổi. Để sửa đổi như một mục, bạn có thể tái gán đối tượng sửa đổi để proxy container:
Đào thông qua các mã nguồn, bạn có thể thấy rằng khi bạn gọi append
trên ListProxy, cuộc gọi append thực sự được gửi cho đối tượng người quản lý qua IPC và sau đó người quản lý gọi thêm vào danh sách được chia sẻ. Điều đó có nghĩa là các số điện thoại đến số append
cần được nhận/bỏ tạm dừng. Trong quá trình giải nén, đối tượng ListProxy được chuyển thành một danh sách Python thông thường, đó là một bản sao của những gì mà ListProxy trỏ tới (hay còn gọi là referent của nó). Đây cũng là noted in the documentation:
Một tính năng quan trọng của các đối tượng proxy là chúng có thể được chuyển qua lại giữa các quá trình. Tuy nhiên, lưu ý rằng nếu một proxy được gửi đến quy trình của người quản lý tương ứng thì việc bỏ chọn nó sẽ tự động tự giới thiệu. Điều này có nghĩa, ví dụ, rằng một đối tượng chia sẻ có thể chứa một giây
Vì vậy, sẽ trở lại ví dụ trên, nếu l [0] là một bản sao của z
, tại sao không cập nhật z
cũng cập nhật l[0]
? Bởi vì bản sao cũng được đăng ký với đối tượng Proxy, do đó, khi bạn thay đổi ListProxy (z
trong ví dụ trên), nó cũng cập nhật tất cả các bản sao đã đăng ký của danh sách (l[0]
trong ví dụ trên). Tuy nhiên, bản sao không biết gì về proxy, vì vậy khi bạn thay đổi bản sao, Proxy sẽ không thay đổi.Vì vậy, để làm ví dụ của bạn hoạt động, bạn cần tạo đối tượng manager.list()
mới mỗi khi bạn muốn sửa đổi danh sách phụ và chỉ cập nhật đối tượng proxy đó trực tiếp, thay vì cập nhật đối tượng đó qua chỉ mục của danh sách mẹ :
#!/usr/bin/python
from multiprocessing import Process, Manager
def worker(x, i, *args):
sub_l = manager.list(x[i])
sub_l.append(i)
x[i] = sub_l
if __name__ == '__main__':
manager = Manager()
x = manager.list([[]]*5)
print x
p = []
for i in range(5):
p.append(Process(target=worker, args=(x, i)))
p[i].start()
for i in range(5):
p[i].join()
print x
Dưới đây là kết quả:
[email protected]:~$ ./multi_weirdness.py
[[0], [1], [2], [3], [4]]
khi bạn gỡ lỗi nó, bạn có thể thiết lập một breakpoint trong việc def (i)? Điều đó có thể không được gọi là – linpingta
@linpingta Tôi đã thêm tuyên bố in trong công nhân (i) và thông báo được in ra. –
Bạn có chắc chắn trong 'worker' mà bạn muốn nối thêm vào' x [i] 'chứ không phải' x' (toàn cầu) không? – beroe