PEP 703: --disable-gil and other small changes (#2979)
* Rename `--without-gil` to `--disable-gil`. Suggested by Inada Naoki. * Add two sections to "Rejected Ideas": - Why Not Deprecate ``PyDict_GetItem`` in Favor of ``PyDict_FetchItem``? - Why Not Use PEP 683 Immortalization? * Expand on Python build modes
This commit is contained in:
parent
b4de31296d
commit
d9503c0be9
96
pep-0703.rst
96
pep-0703.rst
|
@ -8,7 +8,7 @@ Type: Standards Track
|
|||
Content-Type: text/x-rst
|
||||
Created: 09-Jan-2023
|
||||
Python-Version: 3.12
|
||||
Post-History: 09-Jan-2023
|
||||
Post-History: `09-Jan-2023 <https://discuss.python.org/t/22606>`__
|
||||
Resolution:
|
||||
|
||||
|
||||
|
@ -18,7 +18,7 @@ Abstract
|
|||
CPython's global interpreter lock ("GIL") prevents multiple threads
|
||||
from executing Python code at the same time. The GIL is an obstacle
|
||||
to using multi-core CPUs from Python efficiently. This PEP proposes
|
||||
adding a build configuration (``--without-gil``) to CPython to let it
|
||||
adding a build configuration (``--disable-gil``) to CPython to let it
|
||||
run Python code without the global interpreter lock and with the
|
||||
necessary changes needed to make the interpreter thread-safe.
|
||||
|
||||
|
@ -326,10 +326,10 @@ Build Configuration Changes
|
|||
|
||||
The global interpreter lock will remain the default for CPython builds
|
||||
and python.org downloads. A new build configuration flag,
|
||||
``--without-gil`` will be added to the configure script that will
|
||||
``--disable-gil`` will be added to the configure script that will
|
||||
build CPython without the global interpreter lock.
|
||||
|
||||
When built with ``--without-gil``, CPython will define the
|
||||
When built with ``--disable-gil``, CPython will define the
|
||||
``Py_NOGIL`` macro in Python/patchlevel.h. The ABI tag will include
|
||||
the letter "n" (for "nogil").
|
||||
|
||||
|
@ -647,7 +647,7 @@ CPython Free Lists
|
|||
CPython makes use of free lists to speed up the allocation of small,
|
||||
frequently allocated objects like tuples and numbers. These free
|
||||
lists are not thread-safe and will need to be disabled when building
|
||||
Python in the ``--without-gil`` mode.
|
||||
Python in the ``--disable-gil`` mode.
|
||||
|
||||
|
||||
|
||||
|
@ -1280,7 +1280,7 @@ Backwards Compatibility
|
|||
=======================
|
||||
|
||||
This PEP poses a number of backwards compatibility issues when
|
||||
building CPython with the ``--without-gil`` flag, but those issues do
|
||||
building CPython with the ``--disable-gil`` flag, but those issues do
|
||||
not occur when using the default build configuration. Nearly all the
|
||||
backwards compatibility concerns involve the C-API:
|
||||
|
||||
|
@ -1332,14 +1332,14 @@ Distribution
|
|||
This PEP poses new challenges for distributing Python. At least for
|
||||
some time, there will be two versions of Python requiring separately
|
||||
compiled C-API extensions. It may take some time for C-API extension
|
||||
authors to build ``--without-gil`` compatible packages and upload
|
||||
authors to build ``--disable-gil`` compatible packages and upload
|
||||
them to PyPI. Additionally, some authors may be hesitant to support
|
||||
the ``--without-gil`` mode until it has wide adoption, but adoption
|
||||
the ``--disable-gil`` mode until it has wide adoption, but adoption
|
||||
will likely depend on the availability of Python's rich set of
|
||||
extensions.
|
||||
|
||||
To mitigate this, the author will work with Anaconda to distribute
|
||||
a ``--without-gil`` version of Python together with compatible
|
||||
a ``--disable-gil`` version of Python together with compatible
|
||||
packages from conda channels. This centralizes the challenges of
|
||||
building extensions, and the author believes this will enable more
|
||||
people to use Python without the GIL sooner than they would otherwise
|
||||
|
@ -1370,7 +1370,7 @@ The other changes with significant performance impact are:
|
|||
How to Teach This
|
||||
=================
|
||||
|
||||
As part of implementing the ``--without-gil`` mode, the author will
|
||||
As part of implementing the ``--disable-gil`` mode, the author will
|
||||
write a "HOWTO" guide [#howto]_ for making packages compatible when
|
||||
running Python without the GIL.
|
||||
|
||||
|
@ -1531,6 +1531,52 @@ author is not aware of a way to add write barriers to CPython without
|
|||
substantially breaking the C-API.
|
||||
|
||||
|
||||
Why Not Deprecate ``PyDict_GetItem`` in Favor of ``PyDict_FetchItem``?
|
||||
----------------------------------------------------------------------
|
||||
|
||||
This PEP proposes a new API ``PyDict_FetchItem`` which behaves like
|
||||
``PyDict_GetItem``, but returns a new reference instead of a borrowed
|
||||
reference. As described in `Borrowed References`_, some uses of
|
||||
borrowed references that were safe when running with the GIL are
|
||||
unsafe when running without the GIL and need to be replaced by
|
||||
functions like ``PyDict_FetchItem`` that return new references.
|
||||
|
||||
This PEP does *not* propose deprecating ``PyDict_GetItem`` and similar
|
||||
functions that return borrowed references for a few reasons:
|
||||
|
||||
* Many of the uses of borrowed references are safe, even when running
|
||||
without the GIL. For example, C API functions often use
|
||||
``PyDict_GetItem`` to retrieve items from the keyword
|
||||
argument dictionary. These calls are safe because the keyword
|
||||
argument dictionary is only visible to a single thread.
|
||||
* I tried this approach early on and found that wholesale replacing of
|
||||
``PyDict_GetItem`` with ``PyDict_FetchItem`` frequently introduced
|
||||
new reference counting bugs. In my opinion, the risk of
|
||||
introducing new reference counting bugs generally outweighs the
|
||||
risks of missing a ``PyDict_GetItem`` call that is unsafe without
|
||||
the GIL.
|
||||
|
||||
|
||||
Why Not Use PEP 683 Immortalization?
|
||||
------------------------------------
|
||||
|
||||
Like :pep:`683`, this PEP proposes an immortalization scheme for
|
||||
Python objects, but the PEPs use different bit representations to
|
||||
mark immortal objects. The schemes cannot be identical because this
|
||||
PEP depends on biased reference counting, which has two reference
|
||||
count fields instead of one. The schemes could be made more
|
||||
superficially similar, but it is not clear that would be worthwhile.
|
||||
PEP 683 maintains compatibility with extensions compiled to the
|
||||
stable ABI, and therefore uses the second most significant bit
|
||||
(i.e., 2^62 on 64-bit platforms) to mark immortal objects. Checking
|
||||
that bit typically requires an extra instruction on x86-64 compared
|
||||
with checking the sign bit or one of the low 32 bits. This PEP
|
||||
cannot maintain compatibility with extensions compiled to the stable
|
||||
ABI because of the use of two reference count fields, and so this PEP
|
||||
is free to propose a representation that allows slightly more
|
||||
efficient checks for immortality on x86-64.
|
||||
|
||||
|
||||
Open Issues
|
||||
===========
|
||||
|
||||
|
@ -1548,23 +1594,39 @@ manner.
|
|||
Python Build Modes
|
||||
------------------
|
||||
|
||||
This PEP introduces a new build mode (``--without-gil``) that is not
|
||||
This PEP introduces a new build mode (``--disable-gil``) that is not
|
||||
ABI compatible with the standard build mode. The additional build
|
||||
mode adds complexity for both Python core developers and extension
|
||||
developers. The author believes a worthwhile long-term goal is to
|
||||
combine these build modes and have the global interpreter lock
|
||||
controlled at runtime, possibly disabled by default. The path to
|
||||
this goal remains an open issue.
|
||||
developers. The author believes a worthwhile goal is to combine
|
||||
these build modes and have the global interpreter lock controlled at
|
||||
runtime, possibly disabled by default. The path to this goal remains
|
||||
an open issue, but a possible path might look like the following:
|
||||
|
||||
#. In 2024, CPython 3.13 is released with support for a
|
||||
``--disable-gil`` build time flag. There are two ABIs for
|
||||
CPython, one with the GIL and one without. Extension authors
|
||||
target both ABIs.
|
||||
#. After 2--3 releases, (i.e., in 2026--2027), CPython is released
|
||||
with with the GIL controlled by a runtime environment variable or
|
||||
flag. The GIL is enabled by default. There is only a single ABI.
|
||||
#. After another 2--3 release (i.e., 2028--2030), CPython switches to
|
||||
the GIL being disabled by default. The GIL can still be enabled
|
||||
at runtime via an environment variable or command line flag.
|
||||
|
||||
This PEP covers the first step, with the remaining steps left as open
|
||||
issues. In this scenario, there would be a two to three year period
|
||||
where extension authors would target an extra CPython build per
|
||||
supported CPU architecture and OS.
|
||||
|
||||
|
||||
Mitigations for Single-Threaded Performance
|
||||
-------------------------------------------
|
||||
|
||||
The changes proposed in the PEP will increase execution overhead for
|
||||
``--without-gil`` builds compared to Python builds with the GIL. In
|
||||
``--disable-gil`` builds compared to Python builds with the GIL. In
|
||||
other words, it will have slower single-threaded performance. There
|
||||
are some possible optimizations to reduce execution overhead,
|
||||
especially for ``--without-gil`` builds that only use a single
|
||||
especially for ``--disable-gil`` builds that only use a single
|
||||
thread. These may be worthwhile if a longer term goal is to have a
|
||||
single build mode, but the choice of optimizations and their
|
||||
trade-offs remain an open issue.
|
||||
|
|
Loading…
Reference in New Issue