@@ -1441,111 +1441,10 @@ application).
14411441 list appear empty for the duration, and raises :exc: `ValueError ` if it can
14421442 detect that the list has been mutated during a sort.
14431443
1444- .. _thread-safety-list :
1445-
1446- .. rubric :: Thread safety for list objects
1447-
1448- Reading a single element from a :class: `list ` is
1449- :term: `atomic <atomic operation> `:
1450-
1451- .. code-block ::
1452- :class: green
1453-
1454- lst[i] # list.__getitem__
1455-
1456- The following methods traverse the list and use :term: `atomic <atomic operation> `
1457- reads of each item to perform their function. That means that they may
1458- return results affected by concurrent modifications:
1459-
1460- .. code-block ::
1461- :class: maybe
1462-
1463- item in lst
1464- lst.index(item)
1465- lst.count(item)
1466-
1467- All of the above operations avoid acquiring :term: `per-object locks
1468- <per-object lock> `. They do not block concurrent modifications. Other
1469- operations that hold a lock will not block these from observing intermediate
1470- states.
1471-
1472- All other operations from here on block using the :term: `per-object lock `.
1473-
1474- Writing a single item via ``lst[i] = x `` is safe to call from multiple
1475- threads and will not corrupt the list.
1476-
1477- The following operations return new objects and appear
1478- :term: `atomic <atomic operation> ` to other threads:
1479-
1480- .. code-block ::
1481- :class: good
1482-
1483- lst1 + lst2 # concatenates two lists into a new list
1484- x * lst # repeats lst x times into a new list
1485- lst.copy() # returns a shallow copy of the list
1486-
1487- The following methods that only operate on a single element with no shifting
1488- required are :term: `atomic <atomic operation> `:
1489-
1490- .. code-block ::
1491- :class: good
1492-
1493- lst.append(x) # append to the end of the list, no shifting required
1494- lst.pop() # pop element from the end of the list, no shifting required
1495-
1496- The :meth: `~list.clear ` method is also :term: `atomic <atomic operation> `.
1497- Other threads cannot observe elements being removed.
1498-
1499- The :meth: `~list.sort ` method is not :term: `atomic <atomic operation> `.
1500- Other threads cannot observe intermediate states during sorting, but the
1501- list appears empty for the duration of the sort.
1502-
1503- The following operations may allow :term: `lock-free ` operations to observe
1504- intermediate states since they modify multiple elements in place:
1505-
1506- .. code-block ::
1507- :class: maybe
1508-
1509- lst.insert(idx, item) # shifts elements
1510- lst.pop(idx) # idx not at the end of the list, shifts elements
1511- lst *= x # copies elements in place
1512-
1513- The :meth: `~list.remove ` method may allow concurrent modifications since
1514- element comparison may execute arbitrary Python code (via
1515- :meth: `~object.__eq__ `).
1516-
1517- :meth: `~list.extend ` is safe to call from multiple threads. However, its
1518- guarantees depend on the iterable passed to it. If it is a :class: `list `, a
1519- :class: `tuple `, a :class: `set `, a :class: `frozenset `, a :class: `dict ` or a
1520- :ref: `dictionary view object <dict-views >` (but not their subclasses), the
1521- ``extend `` operation is safe from concurrent modifications to the iterable.
1522- Otherwise, an iterator is created which can be concurrently modified by
1523- another thread. The same applies to inplace concatenation of a list with
1524- other iterables when using ``lst += iterable ``.
1525-
1526- Similarly, assigning to a list slice with ``lst[i:j] = iterable `` is safe
1527- to call from multiple threads, but ``iterable `` is only locked when it is
1528- also a :class: `list ` (but not its subclasses).
1529-
1530- Operations that involve multiple accesses, as well as iteration, are never
1531- atomic. For example:
1532-
1533- .. code-block ::
1534- :class: bad
1535-
1536- # NOT atomic: read-modify-write
1537- lst[i] = lst[i] + 1
1538-
1539- # NOT atomic: check-then-act
1540- if lst:
1541- item = lst.pop()
1542-
1543- # NOT thread-safe: iteration while modifying
1544- for item in lst:
1545- process(item) # another thread may modify lst
1444+ .. seealso ::
15461445
1547- Consider external synchronization when sharing :class: `list ` instances
1548- across threads. See :ref: `freethreading-python-howto ` for more information .
1446+ For detailed information on thread-safety guarantees for :class: `list `
1447+ objects, see :ref: `thread-safety-list ` .
15491448
15501449
15511450.. _typesseq-tuple :
@@ -5593,144 +5492,10 @@ can be used interchangeably to index the same dictionary entry.
55935492 of a :class: `dict `.
55945493
55955494
5596- .. _thread-safety-dict :
5597-
5598- .. rubric :: Thread safety for dict objects
5599-
5600- Creating a dictionary with the :class: `dict ` constructor is atomic when the
5601- argument to it is a :class: `dict ` or a :class: `tuple `. When using the
5602- :meth: `dict.fromkeys ` method, dictionary creation is atomic when the
5603- argument is a :class: `dict `, :class: `tuple `, :class: `set ` or
5604- :class: `frozenset `.
5605-
5606- The following operations and functions are :term: `lock-free ` and
5607- :term: `atomic <atomic operation> `.
5608-
5609- .. code-block ::
5610- :class: good
5611-
5612- d[key] # dict.__getitem__
5613- d.get(key) # dict.get
5614- key in d # dict.__contains__
5615- len(d) # dict.__len__
5616-
5617- All other operations from here on hold the :term: `per-object lock `.
5618-
5619- Writing or removing a single item is safe to call from multiple threads
5620- and will not corrupt the dictionary:
5621-
5622- .. code-block ::
5623- :class: good
5624-
5625- d[key] = value # write
5626- del d[key] # delete
5627- d.pop(key) # remove and return
5628- d.popitem() # remove and return last item
5629- d.setdefault(key, v) # insert if missing
5630-
5631- These operations may compare keys using :meth: `~object.__eq__ `, which can
5632- execute arbitrary Python code. During such comparisons, the dictionary may
5633- be modified by another thread. For built-in types like :class: `str `,
5634- :class: `int `, and :class: `float `, that implement :meth: `~object.__eq__ ` in C,
5635- the underlying lock is not released during comparisons and this is not a
5636- concern.
5637-
5638- The following operations return new objects and hold the :term: `per-object lock `
5639- for the duration of the operation:
5640-
5641- .. code-block ::
5642- :class: good
5643-
5644- d.copy() # returns a shallow copy of the dictionary
5645- d | other # merges two dicts into a new dict
5646- d.keys() # returns a new dict_keys view object
5647- d.values() # returns a new dict_values view object
5648- d.items() # returns a new dict_items view object
5649-
5650- The :meth: `~dict.clear ` method holds the lock for its duration. Other
5651- threads cannot observe elements being removed.
5652-
5653- The following operations lock both dictionaries. For :meth: `~dict.update `
5654- and ``|= ``, this applies only when the other operand is a :class: `dict `
5655- that uses the standard dict iterator (but not subclasses that override
5656- iteration). For equality comparison, this applies to :class: `dict ` and
5657- its subclasses:
5658-
5659- .. code-block ::
5660- :class: good
5661-
5662- d.update(other_dict) # both locked when other_dict is a dict
5663- d |= other_dict # both locked when other_dict is a dict
5664- d == other_dict # both locked for dict and subclasses
5665-
5666- All comparison operations also compare values using :meth: `~object.__eq__ `,
5667- so for non-built-in types the lock may be released during comparison.
5668-
5669- :meth: `~dict.fromkeys ` locks both the new dictionary and the iterable
5670- when the iterable is exactly a :class: `dict `, :class: `set `, or
5671- :class: `frozenset ` (not subclasses):
5672-
5673- .. code-block ::
5674- :class: good
5675-
5676- dict.fromkeys(a_dict) # locks both
5677- dict.fromkeys(a_set) # locks both
5678- dict.fromkeys(a_frozenset) # locks both
5679-
5680- When updating from a non-dict iterable, only the target dictionary is
5681- locked. The iterable may be concurrently modified by another thread:
5682-
5683- .. code-block ::
5684- :class: maybe
5685-
5686- d.update(iterable) # iterable is not a dict: only d locked
5687- d |= iterable # iterable is not a dict: only d locked
5688- dict.fromkeys(iterable) # iterable is not a dict/set/frozenset: only result locked
5689-
5690- Operations that involve multiple accesses, as well as iteration, are never
5691- atomic:
5692-
5693- .. code-block ::
5694- :class: bad
5695-
5696- # NOT atomic: read-modify-write
5697- d[key] = d[key] + 1
5698-
5699- # NOT atomic: check-then-act (TOCTOU)
5700- if key in d:
5701- del d[key]
5702-
5703- # NOT thread-safe: iteration while modifying
5704- for key, value in d.items():
5705- process(key) # another thread may modify d
5706-
5707- To avoid time-of-check to time-of-use (TOCTOU) issues, use atomic
5708- operations or handle exceptions:
5709-
5710- .. code-block ::
5711- :class: good
5712-
5713- # Use pop() with default instead of check-then-delete
5714- d.pop(key, None)
5715-
5716- # Or handle the exception
5717- try:
5718- del d[key]
5719- except KeyError:
5720- pass
5721-
5722- To safely iterate over a dictionary that may be modified by another
5723- thread, iterate over a copy:
5724-
5725- .. code-block ::
5726- :class: good
5727-
5728- # Make a copy to iterate safely
5729- for key, value in d.copy().items():
5730- process(key)
5495+ .. seealso ::
57315496
5732- Consider external synchronization when sharing :class: `dict ` instances
5733- across threads. See :ref: `freethreading-python-howto ` for more information .
5497+ For detailed information on thread-safety guarantees for :class: `dict `
5498+ objects, see :ref: `thread-safety-dict ` .
57345499
57355500
57365501.. _dict-views :
0 commit comments