Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 76 additions & 9 deletions peps/pep-0797.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,18 @@ For example:
interp.prepare_main(file=proxy)
interp.exec("file.write('I didn't expect the Spanish Inquisition')")

Terminology
===========

This PEP uses the term "share", "sharing", and "shareable" to refer to objects
that are *natively* shareable between interpreters. This differs from :pep:`734`,
which uses these terms to also describe an object that supports the :mod:`pickle`
module.

In addition to the new :class:`~concurrent.interpreters.SharedObjectProxy` type,
the list of natively shareable objects can be found in :ref:`the documentation
<interp-object-sharing>`.

Motivation
==========

Expand Down Expand Up @@ -69,21 +81,56 @@ implementing other methods to share objects between interpreters.
Specification
=============

.. class:: concurrent.interpreters.SharedObjectProxy

.. function:: concurrent.interpreters.share(obj)

Ensure *obj* is natively shareable.

If *obj* is natively shareable, this function does not create a proxy and
simply returns *obj*. Otherwise, *obj* is wrapped in an instance of
:class:`~concurrent.interpreters.SharedObjectProxy` and returned.

If *obj* has a :meth:`~object.__share__` method, the default behavior of
this function is overridden; the object's ``__share__`` method will be
called to convert *obj* into a natively shareable version of itself, which
will be returned by this function. If the object returned by ``__share__``
is not natively shareable, this function raises an exception.

The behavior of this function is roughly equivalent to:

.. code-block:: python

def share(obj):
if _is_natively_shareable(obj):
return obj

if hasattr(obj, "__share__"):
shareable = obj.__share__()
if not _is_natively_shareable(shareable):
raise TypeError(f"__share__() returned unshareable object: {shareable!r}")

return shareable

return SharedObjectProxy(obj)


.. class:: concurrent.interpreters.SharedObjectProxy(obj)

A proxy type that allows access to an object across multiple interpreters.
This cannot be constructed from Python; instead, use the
:func:`~concurrent.interpreters.share` function.
Instances of this object are natively shareable between subinterpreters.

Unlike :func:`~concurrent.interpreters.share`, *obj* will always be wrapped,
even if it is natively shareable already or already a ``SharedObjectProxy``
instance. The object's :meth:`~object.__share__` method is not invoked if
it is available. Thus, prefer using ``share`` where possible.

.. function:: concurrent.interpreters.share(obj)

Wrap *obj* in a :class:`~concurrent.interpreters.SharedObjectProxy`,
allowing it to be used in other interpreter APIs as if it were natively
shareable.
.. function:: object.__share__()

If *obj* is natively shareable, this function does not create a proxy and
simply returns *obj*.
Return a natively shareable version of the current object. This includes
shared object proxies, as they are also natively shareable. Objects composed
of shared object proxies are also allowed, such as a :class:`tuple` whose
elements are :class:`~concurrent.interpreters.SharedObjectProxy` instances.


Interpreter Switching
Expand All @@ -108,6 +155,26 @@ accessed in subinterpreters through a proxy:
interp.exec("foo()")


Method Proxying
---------------

Methods on a shared object proxy will switch to their owning interpreter when
accessed. In addition, any arguments passed to the method are implicitly called
with :func:`~concurrent.interpreters.share` to ensure they are shareable (only
types that are not natively shareable are wrapped in a proxy). The same happens
to the return value of the method.

For example, the ``__add__`` method on an object proxy is roughly equivalent
to the following code:

.. code-block:: python

def __add__(self, other):
with self.switch_interpreter():
result = self.value.__add__(share(other))
return share(result)


Multithreaded Scaling
---------------------

Expand Down
Loading