You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A thread-safe dictionary. It has a few notable methods:
76
-
77
-
-`assign_atomic()`
78
-
-`get_locked()`
79
-
-`update_atomic()`
75
+
A thread-safe dictionary. It has several atomic methods for safe concurrent operations:
76
+
77
+
-`assign_atomic()` - Atomically assign a value to a key
78
+
-`update_atomic()` - Atomically update a value using a function
79
+
-`remove_atomic()` - Atomically remove a key and return its value
80
+
-`put_if_absent()` - Atomically put a value only if the key doesn't exist
81
+
-`replace_if_present()` - Atomically replace a value only if the key exists
82
+
-`replace_if_equal()` - Atomically replace a value only if it equals the expected value
83
+
-`remove_if_exists()` - Atomically remove a key if it exists
84
+
-`get_and_remove()` - Atomically get and remove a value
85
+
-`get_locked()` - Context manager for safe read-modify-write operations
80
86
81
87
#### ConcurrentDictionary's `assign_atomic()`
82
88
83
89
Assigns a dictionary value under a key in a thread-safe way.
84
90
While `dict["somekey"] = value` is allowed, it's best to use `assign_atomic()` for clarity of intent. Using normal assignment will work but raise a UserWarning.
85
91
92
+
#### ConcurrentDictionary's `remove_atomic()`
93
+
94
+
Atomically removes a key from the dictionary and returns its value, or None if the key doesn't exist.
95
+
96
+
```python
97
+
from concurrent_collections import ConcurrentDictionary
98
+
99
+
d = ConcurrentDictionary({'x': 1, 'y': 2})
100
+
value = d.remove_atomic('x') # Returns 1, removes 'x'
101
+
```
102
+
103
+
#### ConcurrentDictionary's `put_if_absent()`
104
+
105
+
Atomically puts a value for a key only if the key is not already present. Returns the existing value if the key exists, None if the key was added.
106
+
107
+
```python
108
+
from concurrent_collections import ConcurrentDictionary
109
+
110
+
d = ConcurrentDictionary({'x': 1})
111
+
existing = d.put_if_absent('x', 2) # Returns 1, no change
replaced = d.replace_if_equal('x', 1, 3) # Returns False (current value is 2)
137
+
```
86
138
87
139
#### ConcurrentDictionary's `get_locked()`
88
140
@@ -126,6 +178,70 @@ Additionally, there are [other queue classes in the `multiprocessing` module](ht
126
178
-`SimpleQueue` (again)
127
179
128
180
181
+
## Equality and Identity Semantics
182
+
183
+
### ConcurrentBag Equality
184
+
185
+
`ConcurrentBag` compares as a **multiset** - order doesn't matter, but element frequency does:
186
+
187
+
```python
188
+
from concurrent_collections import ConcurrentBag
189
+
190
+
# These are equal (same elements, same frequencies)
191
+
bag1 = ConcurrentBag([1, 2, 2, 3])
192
+
bag2 = ConcurrentBag([2, 1, 3, 2])
193
+
assert bag1 == bag2 # True
194
+
195
+
# These are not equal (different frequencies)
196
+
bag3 = ConcurrentBag([1, 2, 3, 3])
197
+
assert bag1 != bag3 # True
198
+
```
199
+
200
+
### ConcurrentQueue Equality
201
+
202
+
`ConcurrentQueue` compares elements in order, taking snapshots for consistency during concurrent operations:
203
+
204
+
```python
205
+
from concurrent_collections import ConcurrentQueue
206
+
207
+
# These are equal (same elements, same order)
208
+
queue1 = ConcurrentQueue([1, 2, 3])
209
+
queue2 = ConcurrentQueue([1, 2, 3])
210
+
assert queue1 == queue2 # True
211
+
212
+
# These are not equal (different order)
213
+
queue3 = ConcurrentQueue([3, 2, 1])
214
+
assert queue1 != queue3 # True
215
+
```
216
+
217
+
### ConcurrentDictionary Equality
218
+
219
+
`ConcurrentDictionary` compares key-value pairs, order doesn't matter:
220
+
221
+
```python
222
+
from concurrent_collections import ConcurrentDictionary
223
+
224
+
# These are equal (same key-value pairs)
225
+
dict1 = ConcurrentDictionary({'a': 1, 'b': 2})
226
+
dict2 = ConcurrentDictionary({'b': 2, 'a': 1})
227
+
assert dict1 == dict2 # True
228
+
229
+
# These are not equal (different values)
230
+
dict3 = ConcurrentDictionary({'a': 1, 'b': 3})
231
+
assert dict1 != dict3 # True
232
+
```
233
+
234
+
## Thread Safety Guarantees
235
+
236
+
All collections provide the following guarantees:
237
+
238
+
1.**Atomic Operations**: All individual operations (append, remove, get, set) are atomic
239
+
2.**Consistent Snapshots**: Iteration and equality comparisons take consistent snapshots
240
+
3.**No Race Conditions**: Multiple threads can safely access and modify the collections
241
+
4.**Identity Consistency**: Hash values and equality comparisons are consistent within a single operation
242
+
243
+
**Note**: While individual operations are thread-safe, compound operations (like checking length then conditionally modifying) should use the provided atomic methods or context managers to ensure consistency.
0 commit comments