Skip to content

Commit 5b8e28b

Browse files
PEP 734: Simplify Explanations of "Shareable" Objects (#4374)
1 parent d460355 commit 5b8e28b

File tree

1 file changed

+51
-99
lines changed

1 file changed

+51
-99
lines changed

peps/pep-0734.rst

Lines changed: 51 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -356,9 +356,10 @@ Attributes and methods:
356356
Bind one or more objects in the interpreter's ``__main__`` module.
357357

358358
The keyword argument names will be used as the attribute names.
359-
The values will be bound as new objects, though exactly equivalent
360-
to the original. Only objects specifically supported for passing
361-
between interpreters are allowed. See `Shareable Objects`_.
359+
For most objects a copy will be bound in the interpreter, with
360+
pickle used in between. For some objects, like ``memoryview``,
361+
the underlying data will be shared between the interpreters.
362+
See `Shareable Objects`_.
362363

363364
``prepare_main()`` is helpful for initializing the
364365
globals for an interpreter before running code in it.
@@ -449,12 +450,14 @@ As with other queues in Python, for each "put" the object is added to
449450
the back and each "get" pops the next one off the front. Every added
450451
object will be popped off in the order it was pushed on.
451452

452-
Only objects that are specifically supported for passing
453-
between interpreters may be sent through an ``interpreters.Queue``.
454-
Note that the actual objects aren't sent, but rather their
455-
underlying data. However, the popped object will still be
456-
strictly equivalent to the original.
457-
See `Shareable Objects`_.
453+
Any object that can be pickled may be sent through an
454+
``interpreters.Queue``.
455+
456+
Note that the actual objects aren't sent, but rather their underlying
457+
data is sent. The resulting object is strictly equivalent to the
458+
original. For most objects the underlying data is serialized (e.g.
459+
pickled). In a few cases, like with ``memoryview``, the underlying data
460+
is sent (and shared) without serialization. See `Shareable Objects`_.
458461

459462
The module defines the following functions:
460463

@@ -514,23 +517,17 @@ Attributes and methods:
514517
This is only a snapshot of the state at the time of the call.
515518
Other threads or interpreters may cause this to change.
516519

517-
* ``put(obj, timeout=None, *, syncobj=None)``
520+
* ``put(obj, timeout=None)``
518521
Add the object to the queue.
519522

520523
If ``maxsize > 0`` and the queue is full then this blocks until
521524
a free slot is available. If *timeout* is a positive number
522525
then it only blocks at least that many seconds and then raises
523526
``interpreters.QueueFull``. Otherwise is blocks forever.
524527

525-
If "syncobj" is true then the object must be
526-
`shareable <Shareable Objects_>`_, which means the object's data
527-
is passed through rather than the object itself.
528-
If "syncobj" is false then all objects are supported. However,
529-
there are some performance penalties and all objects are copies
530-
(e.g. via pickle). Thus mutable objects will never be
531-
automatically synchronized between interpreters.
532-
If "syncobj" is None (the default) then the queue's default
533-
value is used.
528+
Nearly all objects can be sent through the queue. In a few cases,
529+
like with ``memoryview``, the underlying data is actually shared,
530+
rather than just copied. See `Shareable Objects`_.
534531

535532
If an object is still in the queue, and the interpreter which put
536533
it in the queue (i.e. to which it belongs) is destroyed, then the
@@ -539,7 +536,7 @@ Attributes and methods:
539536
sentinel or to raise an exception for the corresponding ``get()``
540537
call.)
541538

542-
* ``put_nowait(obj, *, syncobj=None)``
539+
* ``put_nowait(obj``
543540
Like ``put()`` but effectively with an immediate timeout.
544541
Thus if the queue is full, it immediately raises
545542
``interpreters.QueueFull``.
@@ -558,51 +555,41 @@ Attributes and methods:
558555
Shareable Objects
559556
-----------------
560557

561-
``Interpreter.prepare_main()`` only works with "shareable" objects.
562-
The same goes for ``interpreters.Queue`` (optionally).
563-
564558
A "shareable" object is one which may be passed from one interpreter
565-
to another. The object is not necessarily actually directly shared
566-
by the interpreters. However, even if it isn't, the shared object
567-
should be treated as though it *were* shared directly. That's a
568-
strong equivalence guarantee for all shareable objects.
569-
(See below.)
570-
571-
For some types (builtin singletons), the actual object is shared.
572-
For some, the object's underlying data is actually shared but each
573-
interpreter has a distinct object wrapping that data. For all other
574-
shareable types, a strict copy or proxy is made such that the
575-
corresponding objects continue to match exactly. In cases where
576-
the underlying data is complex but must be copied (e.g. ``tuple``),
577-
the data is serialized as efficiently as possible.
578-
579-
Shareable objects must be specifically supported internally
580-
by the Python runtime. However, there is no restriction against
581-
adding support for more types later.
582-
583-
Here's the initial list of supported objects:
584-
585-
* ``str``
586-
* ``bytes``
587-
* ``int``
588-
* ``float``
589-
* ``bool`` (``True``/``False``)
590-
* ``None``
591-
* ``tuple`` (only with shareable items)
592-
* ``interpreters.Queue``
593-
* ``memoryview`` (underlying buffer actually shared)
594-
595-
Note that the last two on the list, queues and ``memoryview``, are
596-
technically mutable data types, whereas the rest are not. When any
597-
interpreters share mutable data there is always a risk of data races.
598-
Cross-interpreter safety, including thread-safety, is a fundamental
599-
feature of queues.
600-
601-
However, ``memoryview`` does not have any native accommodations.
602-
The user is responsible for managing thread-safety, whether passing
603-
a token back and forth through a queue to indicate safety
604-
(see `Synchronization`_), or by assigning sub-range exclusivity
605-
to individual interpreters.
559+
to another. The object is not actually directly shared by the
560+
interpreters. However, the shared object should be treated as though
561+
it *were* shared directly, with caveats for mutability.
562+
563+
All objects that can be pickled are shareable. Thus, nearly every
564+
object is shareable. ``interpreters.Queue`` objects are also shareable.
565+
566+
In nearly every case where an object is sent to an interpreter, whether
567+
with ``interp.prepare_main()`` or ``queue.put()``, the actual object
568+
is not sent. Instead, the object's underlying data is sent. For
569+
most objects the object is pickled and the receiving
570+
interpreter unpickles it.
571+
572+
A notable exception is objects which implement the "buffer" protocol,
573+
like ``memoryview``. Their underlying ``Py_buffer`` is actually shared
574+
between interpreters. ``interp.prepare_main()`` and ``queue.get()``
575+
wrap the buffer in a new ``memoryview`` object.
576+
577+
For most mutable objects, when one is sent to another interpreter, it is
578+
copied. Thus any changes to the original or to the copy will never be
579+
synchronized to the other. Mutable objects shared through pickling fall
580+
into this category. However, ``interpreters.Queue`` and objects that
581+
implement the buffer protocol are notable cases where the underlying
582+
data *is* shared between interpreters, so objects stay synchronized.
583+
584+
When interpreters genuinely share mutable data there is always a risk
585+
of data races. Cross-interpreter safety, including thread-safety,
586+
is a fundamental feature of ``interpreters.Queue``.
587+
588+
However, the buffer protocol (i.e. ``Py_buffer``) does not have any
589+
native accommodations against data races. Instead, the user is
590+
responsible for managing thread-safety, whether passing a token back
591+
and forth through a queue to indicate safety (see `Synchronization`_),
592+
or by assigning sub-range exclusivity to individual interpreters.
606593

607594
Most objects will be shared through queues (``interpreters.Queue``),
608595
as interpreters communicate information between each other.
@@ -612,23 +599,6 @@ to set up an interpreter prior to running code in it. However,
612599
to provide another interpreter with a means
613600
of further communication.
614601

615-
Finally, a reminder: for a few types the actual object is shared,
616-
whereas for the rest only the underlying data is shared, whether
617-
as a copy or through a proxy. Regardless, it always preserves
618-
the strong equivalence guarantee of "shareable" objects.
619-
620-
The guarantee is that a shared object in one interpreter is strictly
621-
equivalent to the corresponding object in the other interpreter.
622-
In other words, the two objects will be indistinguishable from each
623-
other. The shared object should be treated as though the original
624-
had been shared directly, whether or not it actually was.
625-
That's a slightly different and stronger promise than just equality.
626-
627-
The guarantee is especially important for mutable objects, like
628-
``Interpreters.Queue`` and ``memoryview``. Mutating the object
629-
in one interpreter will always be reflected immediately in every
630-
other interpreter sharing the object.
631-
632602
Synchronization
633603
---------------
634604

@@ -1007,24 +977,6 @@ in the calling interpreter. This is because ``Interpreter.call()`` is
1007977
a higher level method that uses pickle to support objects that can't
1008978
normally be passed between interpreters.
1009979

1010-
Limited Object Sharing
1011-
----------------------
1012-
1013-
As noted in `Interpreter Isolation`_, only a small number of builtin
1014-
objects may be truly shared between interpreters. In all other cases
1015-
objects can only be shared indirectly, through copies or proxies.
1016-
1017-
The set of objects that are shareable as copies through queues
1018-
(and ``Interpreter.prepare_main()``) is limited for the sake of
1019-
efficiency.
1020-
1021-
Supporting sharing of *all* objects is possible (via pickle)
1022-
but not part of this proposal. For one thing, it's helpful to know
1023-
in those cases that only an efficient implementation is being used.
1024-
Furthermore, in those cases supporting mutable objects via pickling
1025-
would violate the guarantee that "shared" objects be equivalent
1026-
(and stay that way).
1027-
1028980
Objects vs. ID Proxies
1029981
----------------------
1030982

0 commit comments

Comments
 (0)