[3.14] gh-142518: Document thread-safety guarantees of list operations (GH-142519) (#143736)

* Add everything to code blocks
* Improve wording around atomicity; specify exact types
* Better explain lock-free and atomicity
(cherry picked from commit 1de46715ec50c7ae0b8e8671287239771c121e68)

Co-authored-by: Lysandros Nikolaou <lisandrosnik@gmail.com>
This commit is contained in:
Miss Islington (bot) 2026-01-12 17:55:14 +01:00 committed by GitHub
parent 78ea9eb340
commit 341e086d45
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1441,6 +1441,109 @@ application).
list appear empty for the duration, and raises :exc:`ValueError` if it can
detect that the list has been mutated during a sort.
.. admonition:: Thread safety
Reading a single element from a :class:`list` is
:term:`atomic <atomic operation>`:
.. code-block::
:class: green
lst[i] # list.__getitem__
The following methods traverse the list and use :term:`atomic <atomic operation>`
reads of each item to perform their function. That means that they may
return results affected by concurrent modifications:
.. code-block::
:class: maybe
item in lst
lst.index(item)
lst.count(item)
All of the above methods/operations are also lock-free. They do not block
concurrent modifications. Other operations that hold a lock will not block
these from observing intermediate states.
All other operations from here on block using the per-object lock.
Writing a single item via ``lst[i] = x`` is safe to call from multiple
threads and will not corrupt the list.
The following operations return new objects and appear
:term:`atomic <atomic operation>` to other threads:
.. code-block::
:class: good
lst1 + lst2 # concatenates two lists into a new list
x * lst # repeats lst x times into a new list
lst.copy() # returns a shallow copy of the list
Methods that only operate on a single elements with no shifting required are
:term:`atomic <atomic operation>`:
.. code-block::
:class: good
lst.append(x) # append to the end of the list, no shifting required
lst.pop() # pop element from the end of the list, no shifting required
The :meth:`~list.clear` method is also :term:`atomic <atomic operation>`.
Other threads cannot observe elements being removed.
The :meth:`~list.sort` method is not :term:`atomic <atomic operation>`.
Other threads cannot observe intermediate states during sorting, but the
list appears empty for the duration of the sort.
The following operations may allow lock-free operations to observe
intermediate states since they modify multiple elements in place:
.. code-block::
:class: maybe
lst.insert(idx, item) # shifts elements
lst.pop(idx) # idx not at the end of the list, shifts elements
lst *= x # copies elements in place
The :meth:`~list.remove` method may allow concurrent modifications since
element comparison may execute arbitrary Python code (via
:meth:`~object.__eq__`).
:meth:`~list.extend` is safe to call from multiple threads. However, its
guarantees depend on the iterable passed to it. If it is a :class:`list`, a
:class:`tuple`, a :class:`set`, a :class:`frozenset`, a :class:`dict` or a
:ref:`dictionary view object <dict-views>` (but not their subclasses), the
``extend`` operation is safe from concurrent modifications to the iterable.
Otherwise, an iterator is created which can be concurrently modified by
another thread. The same applies to inplace concatenation of a list with
other iterables when using ``lst += iterable``.
Similarly, assigning to a list slice with ``lst[i:j] = iterable`` is safe
to call from multiple threads, but ``iterable`` is only locked when it is
also a :class:`list` (but not its subclasses).
Operations that involve multiple accesses, as well as iteration, are never
atomic. For example:
.. code-block::
:class: bad
# NOT atomic: read-modify-write
lst[i] = lst[i] + 1
# NOT atomic: check-then-act
if lst:
item = lst.pop()
# NOT thread-safe: iteration while modifying
for item in lst:
process(item) # another thread may modify lst
Consider external synchronization when sharing :class:`list` instances
across threads. See :ref:`freethreading-python-howto` for more information.
.. _typesseq-tuple: