@@ -5593,142 +5593,144 @@ can be used interchangeably to index the same dictionary entry.
55935593 of a :class: `dict `.
55945594
55955595
5596- .. admonition :: Thread safety
5596+ .. _ thread- safety-dict :
55975597
5598- Creating a dictionary with the :class: `dict ` constructor is atomic when the
5599- argument to it is a :class: `dict ` or a :class: `tuple `. When using the
5600- :meth: `dict.fromkeys ` method, dictionary creation is atomic when the
5601- argument is a :class: `dict `, :class: `tuple `, :class: `set ` or
5602- :class: `frozenset `.
5598+ .. rubric :: Thread safety for dict objects
56035599
5604- The following operations and functions are lock-free and
5605- :term: `atomic <atomic operation> `.
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 `.
56065605
5607- .. code-block ::
5608- :class: good
5606+ The following operations and functions are :term: ` lock-free ` and
5607+ :term: ` atomic <atomic operation> `.
56095608
5610- d[key] # dict.__getitem__
5611- d.get(key) # dict.get
5612- key in d # dict.__contains__
5613- len(d) # dict.__len__
5609+ .. code-block ::
5610+ :class: good
56145611
5615- All other operations from here on hold the per-object lock.
5612+ d[key] # dict.__getitem__
5613+ d.get(key) # dict.get
5614+ key in d # dict.__contains__
5615+ len(d) # dict.__len__
56165616
5617- Writing or removing a single item is safe to call from multiple threads
5618- and will not corrupt the dictionary:
5617+ All other operations from here on hold the :term: `per-object lock `.
56195618
5620- .. code-block ::
5621- :class: good
5619+ Writing or removing a single item is safe to call from multiple threads
5620+ and will not corrupt the dictionary:
56225621
5623- d[key] = value # write
5624- del d[key] # delete
5625- d.pop(key) # remove and return
5626- d.popitem() # remove and return last item
5627- d.setdefault(key, v) # insert if missing
5622+ .. code-block ::
5623+ :class: good
56285624
5629- These operations may compare keys using :meth: `~object.__eq__ `, which can
5630- execute arbitrary Python code. During such comparisons, the dictionary may
5631- be modified by another thread. For built-in types like :class: `str `,
5632- :class: `int `, and :class: `float `, that implement :meth: `~object.__eq__ ` in C,
5633- the underlying lock is not released during comparisons and this is not a
5634- concern.
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
56355630
5636- The following operations return new objects and hold the per-object lock
5637- for the duration of the operation:
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.
56385637
5639- .. code-block ::
5640- :class: good
5638+ The following operations return new objects and hold the :term: ` per-object lock `
5639+ for the duration of the operation:
56415640
5642- d.copy() # returns a shallow copy of the dictionary
5643- d | other # merges two dicts into a new dict
5644- d.keys() # returns a new dict_keys view object
5645- d.values() # returns a new dict_values view object
5646- d.items() # returns a new dict_items view object
5641+ .. code-block ::
5642+ :class: good
56475643
5648- The :meth: `~dict.clear ` method holds the lock for its duration. Other
5649- threads cannot observe elements being removed.
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
56505649
5651- The following operations lock both dictionaries. For :meth: `~dict.update `
5652- and ``|= ``, this applies only when the other operand is a :class: `dict `
5653- that uses the standard dict iterator (but not subclasses that override
5654- iteration). For equality comparison, this applies to :class: `dict ` and
5655- its subclasses:
5650+ The :meth: `~dict.clear ` method holds the lock for its duration. Other
5651+ threads cannot observe elements being removed.
56565652
5657- .. code-block ::
5658- :class: good
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:
56595658
5660- d.update(other_dict) # both locked when other_dict is a dict
5661- d |= other_dict # both locked when other_dict is a dict
5662- d == other_dict # both locked for dict and subclasses
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
56635665
5664- All comparison operations also compare values using :meth: `~object.__eq__ `,
5665- so for non-built-in types the lock may be released during comparison.
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.
56665668
5667- :meth: `~dict.fromkeys ` locks both the new dictionary and the iterable
5668- when the iterable is exactly a :class: `dict `, :class: `set `, or
5669- :class: `frozenset ` (not subclasses):
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):
56705672
5671- .. code-block ::
5672- :class: good
5673+ .. code-block ::
5674+ :class: good
56735675
5674- dict.fromkeys(a_dict) # locks both
5675- dict.fromkeys(a_set) # locks both
5676- dict.fromkeys(a_frozenset) # locks both
5676+ dict.fromkeys(a_dict) # locks both
5677+ dict.fromkeys(a_set) # locks both
5678+ dict.fromkeys(a_frozenset) # locks both
56775679
5678- When updating from a non-dict iterable, only the target dictionary is
5679- locked. The iterable may be concurrently modified by another thread:
5680+ When updating from a non-dict iterable, only the target dictionary is
5681+ locked. The iterable may be concurrently modified by another thread:
56805682
5681- .. code-block ::
5682- :class: maybe
5683+ .. code-block ::
5684+ :class: maybe
56835685
5684- d.update(iterable) # iterable is not a dict: only d locked
5685- d |= iterable # iterable is not a dict: only d locked
5686- dict.fromkeys(iterable) # iterable is not a dict/set/frozenset: only result locked
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
56875689
5688- Operations that involve multiple accesses, as well as iteration, are never
5689- atomic:
5690+ Operations that involve multiple accesses, as well as iteration, are never
5691+ atomic:
56905692
5691- .. code-block ::
5692- :class: bad
5693+ .. code-block ::
5694+ :class: bad
56935695
5694- # NOT atomic: read-modify-write
5695- d[key] = d[key] + 1
5696+ # NOT atomic: read-modify-write
5697+ d[key] = d[key] + 1
56965698
5697- # NOT atomic: check-then-act (TOCTOU)
5698- if key in d:
5699- del d[key]
5699+ # NOT atomic: check-then-act (TOCTOU)
5700+ if key in d:
5701+ del d[key]
57005702
5701- # NOT thread-safe: iteration while modifying
5702- for key, value in d.items():
5703- process(key) # another thread may modify d
5703+ # NOT thread-safe: iteration while modifying
5704+ for key, value in d.items():
5705+ process(key) # another thread may modify d
57045706
5705- To avoid time-of-check to time-of-use (TOCTOU) issues, use atomic
5706- operations or handle exceptions:
5707+ To avoid time-of-check to time-of-use (TOCTOU) issues, use atomic
5708+ operations or handle exceptions:
57075709
5708- .. code-block ::
5709- :class: good
5710+ .. code-block ::
5711+ :class: good
57105712
5711- # Use pop() with default instead of check-then-delete
5712- d.pop(key, None)
5713+ # Use pop() with default instead of check-then-delete
5714+ d.pop(key, None)
57135715
5714- # Or handle the exception
5715- try:
5716- del d[key]
5717- except KeyError:
5718- pass
5716+ # Or handle the exception
5717+ try:
5718+ del d[key]
5719+ except KeyError:
5720+ pass
57195721
5720- To safely iterate over a dictionary that may be modified by another
5721- thread, iterate over a copy:
5722+ To safely iterate over a dictionary that may be modified by another
5723+ thread, iterate over a copy:
57225724
5723- .. code-block ::
5724- :class: good
5725+ .. code-block ::
5726+ :class: good
57255727
5726- # Make a copy to iterate safely
5727- for key, value in d.copy().items():
5728- process(key)
5728+ # Make a copy to iterate safely
5729+ for key, value in d.copy().items():
5730+ process(key)
57295731
5730- Consider external synchronization when sharing :class: `dict ` instances
5731- across threads. See :ref: `freethreading-python-howto ` for more information.
5732+ Consider external synchronization when sharing :class: `dict ` instances
5733+ across threads. See :ref: `freethreading-python-howto ` for more information.
57325734
57335735
57345736.. _dict-views :
0 commit comments