-
-
Notifications
You must be signed in to change notification settings - Fork 32.6k
bpo-28053: Allow custom reducer when using multiprocessing #15058
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
5d5b7a4
1fcf62e
4dd92e0
5312390
ac9a8d3
95046c2
c9bf4f5
94c6a66
9d39a34
9ccc067
8704e8e
722f2b9
5e03ffa
8bb0d0d
508a992
984cdd9
6ce49bf
e2cedd1
c99a542
aa9215f
bb7d03e
693e2b6
ee23671
283c691
7154be7
6af4e1c
515bbfd
525239a
87cffec
a31bdae
cd50558
2f117ec
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -1193,6 +1193,103 @@ For example: | |||||
the data in the pipe is likely to become corrupted, because it may become | ||||||
impossible to be sure where the message boundaries lie. | ||||||
|
||||||
Custom Reduction | ||||||
~~~~~~~~~~~~~~~~ | ||||||
|
||||||
.. currentmodule:: multiprocessing | ||||||
|
||||||
Several primitives of the :mod:`multiprocessing` module such as | ||||||
:class:`multiprocessing.Queue`, :class:`multiprocessing.connection.Listener` or | ||||||
:class:`multiprocessing.connection.Server` need to serialize and deserialize Python | ||||||
objects to communicate between processes. Sometimes it is useful to control what | ||||||
serialization is to be used for the transport of data in order to support communication | ||||||
with different versions of Python, use more performant third party tools or custom | ||||||
strategies. | ||||||
|
||||||
For this purpose a set of hooks is available to provide alternate implementations of | ||||||
the reduction mechanism: | ||||||
|
||||||
.. currentmodule:: multiprocessing.reduction | ||||||
|
||||||
.. class:: AbstractPickler(file, protocol) | ||||||
|
||||||
Base class that can be implemented in order to override | ||||||
serialization methods of the reduction machinery used by multiprocessing. | ||||||
|
||||||
.. method:: dump(obj) | ||||||
|
||||||
Write a pickled representation of obj to the open file. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
Defaults to :meth:`pickle.Pickler.dump` | ||||||
|
||||||
.. class:: AbstractUnpickler(bytes_object, *, fix_imports=True, encoding="ASCII", errors="strict") | ||||||
|
||||||
Base class that can be implemented in order to override | ||||||
multiprocessing's default unserialization mechanism. | ||||||
|
||||||
.. method:: load() | ||||||
|
||||||
Read a pickled object hierarchy from the open file and return the | ||||||
reconstituted object hierarchy specified therein. | ||||||
|
||||||
Defaults to :meth:`pickle.Unpickler.load` | ||||||
|
||||||
.. class:: AbstractReducer() | ||||||
|
||||||
Base class providing access to custom ``Pickler`` and ``Unpickler`` | ||||||
classes to be used by ``multiprocessing`` when serializing objects. | ||||||
|
||||||
.. method:: get_pickler_class(): | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
This method must return an subclass of :class:`AbstractPickler` to be used | ||||||
by ``multiprocessing`` when serializing objects. | ||||||
|
||||||
.. method:: get_unpickler_class(): | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
This method must return an subclass of :class:`AbstractUnpickler` to be used | ||||||
by ``multiprocessing`` when unserializing objects. | ||||||
|
||||||
|
||||||
Note that both methods of the :class:`AbstractReducer` are optional. If | ||||||
:meth:`get_pickler_class` (resp. :meth:`get_unpickler_class`) is not | ||||||
implemented, multiprocessing will fallback to the :class:`pickle.Pickler` | ||||||
(resp. :class:`pickle.Unpickler`) class to serialize objects. | ||||||
|
||||||
.. currentmodule:: multiprocessing | ||||||
|
||||||
.. method:: set_reducer(reduction) | ||||||
|
||||||
Sets a reduction instance to be used for serialization and deserialization | ||||||
by the module primitive internals. **reduction** must be an instance of a | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Arguments should be marked in italic: https://devguide.python.org/documenting/#rest-inline-markup |
||||||
subclass of :class:`AbstractReducer`. | ||||||
|
||||||
.. method:: get_reducer() | ||||||
|
||||||
Gets the current reduction class in use by the module's primitive internals. | ||||||
|
||||||
For example, substituting the reducer class to use the :mod:`pickle` protocol | ||||||
version 2 to be able to communicate with a Python 2.x programs.:: | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please change documentation and examples not to reference Python 2 as that long EOL at this point. Just say it in the abstract "communicate with processes using older Python versions" and offer some explanation as to how this is even possible by linking to the relevant APIs in multiprocessing that enable people to create such unexpected monsters. (see #67592 (comment)) Most |
||||||
|
||||||
import multiprocessing | ||||||
from multiprocessing.reduction import AbstractReducer, AbstractPickler | ||||||
|
||||||
class PicklerProtocol2(AbstractPickler): | ||||||
def __init__(self, file, protocol=2, **kwargs): | ||||||
super().__init__(file, protocol, **kwargs) | ||||||
|
||||||
def dump(self, obj): | ||||||
return super().dump(obj) | ||||||
|
||||||
|
||||||
class PickleProtocol2Reducer(AbstractReducer): | ||||||
def get_pickler_class(self): | ||||||
return PicklerProtocol2 | ||||||
|
||||||
multiprocessing.set_reducer(PickleProtocol2Reducer()) | ||||||
|
||||||
Notice that using :meth:`multiprocessing.set_reducer` changes the reducer globally. If | ||||||
changing this setting globally is undesirable you could call :meth:`context.set_reducer`, | ||||||
where *context* is a context object obtained by calling :func:`get_context`. | ||||||
|
||||||
Synchronization primitives | ||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aren't either the
currentmodule
directive or themultiprocessing.*
s in the roles redundant in this part?