Thực tế không cần phải bao gồm hàng đợi trong đối số args
trong trường hợp này, bất kể bạn đang sử dụng nền tảng nào. Lý do là mặc dù nó không giống như bạn đang rõ ràng thông qua hai trường hợp JoinableQueue
cho đứa trẻ, bạn thực sự là - thông qua self
. Bởi vì self
là một cách rõ ràng được truyền cho trẻ, và hai hàng đợi là một phần của self
, chúng sẽ được truyền cho trẻ.
Trên Linux, điều này xảy ra qua os.fork()
, có nghĩa là file descriptor được sử dụng bởi các đối tượng multiprocessing.connection.Connection
rằng Queue
sử dụng nội bộ cho quá trình liên lạc là thừa hưởng bởi đứa trẻ (không sao chép). Các bộ phận khác của Queue
trở thành copy-on-write
, nhưng điều đó là ổn; multiprocessing.Queue
được thiết kế sao cho không có phần nào cần được sao chép thực sự cần phải được đồng bộ giữa hai quy trình. Trên thực tế, nhiều thuộc tính nội bộ được đặt lại sau fork
xảy ra:
Vì vậy, bao gồm Linux. Làm thế nào về Windows? Windows không có fork
, vì vậy nó sẽ cần phải chọn self
để gửi cho đứa trẻ, và điều đó bao gồm tẩy của chúng tôi Queues
. Bây giờ, thông thường nếu bạn cố gắng chọn một số multiprocessing.Queue
, nó không thành công:
>>> import multiprocessing
>>> q = multiprocessing.Queue()
>>> import pickle
>>> pickle.dumps(q)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python2.7/pickle.py", line 1374, in dumps
Pickler(file, protocol).dump(obj)
File "/usr/local/lib/python2.7/pickle.py", line 224, in dump
self.save(obj)
File "/usr/local/lib/python2.7/pickle.py", line 306, in save
rv = reduce(self.proto)
File "/usr/local/lib/python2.7/copy_reg.py", line 84, in _reduce_ex
dict = getstate()
File "/usr/local/lib/python2.7/multiprocessing/queues.py", line 77, in __getstate__
assert_spawning(self)
File "/usr/local/lib/python2.7/multiprocessing/forking.py", line 52, in assert_spawning
' through inheritance' % type(self).__name__
RuntimeError: Queue objects should only be shared between processes through inheritance
Nhưng đây thực sự là giới hạn nhân tạo. multiprocessing.Queue
đối tượng có thể được chọn trong một số trường hợp - cách khác chúng có thể được gửi đến các quy trình con trong Windows? Và quả thực, chúng ta có thể thấy rằng nếu chúng ta nhìn vào thực hiện:
def __getstate__(self):
assert_spawning(self)
return (self._maxsize, self._reader, self._writer,
self._rlock, self._wlock, self._sem, self._opid)
def __setstate__(self, state):
(self._maxsize, self._reader, self._writer,
self._rlock, self._wlock, self._sem, self._opid) = state
self._after_fork()
__getstate__
, được gọi là khi tẩy một ví dụ, có một cuộc gọi assert_spawning
trong nó, mà làm cho chắc chắn chúng tôi đang thực sự đẻ trứng một quá trình trong khi cố gắng dưa chua *. __setstate__
, được gọi là trong khi bỏ chọn, có trách nhiệm gọi số _after_fork
.
Vậy các đối tượng Connection
được sử dụng bởi hàng đợi được duy trì khi chúng ta phải dưa như thế nào?Hóa ra có một mô-đun phụ multiprocessing
thực hiện chính xác điều đó - multiprocessing.reduction
. Các bình luận ở phía trên cùng của mô-đun khẳng định nó khá rõ ràng:
#
# Module to allow connection and socket objects to be transferred
# between processes
#
Trên Windows, các mô-đun cuối cùng sử dụng DuplicateHandle API cung cấp bởi Windows để tạo ra một xử lý trùng lặp quá trình con Connection
đối tượng có thể sử dụng. Vì vậy, trong khi mỗi quá trình được xử lý riêng, chúng là các bản sao chính xác - bất kỳ hành động nào được thực hiện trên một được phản ánh trên khác:
Xử lý trùng lặp đề cập đến cùng một đối tượng. Do đó, mọi thay đổi đối tượng được phản ánh qua cả hai tay cầm . Ví dụ, nếu bạn sao chép một tập tin xử lý, tập tin hiện tại vị trí là luôn luôn giống nhau cho cả hai tay cầm.
* Xem this answer để biết thêm thông tin về assert_spawning
Điều này không hoàn toàn đúng. Trên Linux, quá trình con được chia ra từ cha mẹ, do đó, nó thực sự nhận được một không gian địa chỉ copy-on-write từ cha mẹ. Và trên thực tế, bạn sẽ có thể 'đặt' vào hàng đợi trong phần tử con và' get' kết quả từ phần tử cha mẹ mà không thông qua một cách rõ ràng 'Queue' cho đứa trẻ trên cả Linux * và * Windows. Các trường hợp duy nhất nó dường như không hoạt động là Python 3.4+ với Linux bằng cách sử dụng ngữ cảnh '' spawn'' hoặc ''forkserver''. – dano
Thực ra, tôi lấy lại câu cuối cùng. Đó là do lỗi của tôi. Bạn luôn có thể vượt qua các đối tượng Queue một cách ngầm định, bất kể bối cảnh/nền tảng. – dano
+ dano, câu trả lời hay. Bạn rõ ràng là một guru đa xử lý! – Matt