Skip to content

Commit e66701e

Browse files
committed
Remove cached_method locking logic
Although this logic tried to avoid lock contention, there were still scenarios under which it was possible and could negatively impact users. Removal and adjustment of the documentation puts responsibility for locking/safety onto users, similar to other parts of the stdlib.
1 parent 8ff6b31 commit e66701e

2 files changed

Lines changed: 13 additions & 20 deletions

File tree

Doc/library/functools.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,9 @@ The :mod:`!functools` module defines the following functions:
152152
The *cached_method* does not prevent all possible race conditions in
153153
multi-threaded usage. The function could run more than once on the
154154
same instance, with the same inputs, with the latest run setting the cached
155-
value. However, initialization of the cached method, which happens lazily on
156-
first access, is itself threadsafe.
155+
value. The per-instance cache is lazily initialized on first access (via the
156+
descriptor protocol), so parallel access on a single instance can race to
157+
initialize.
157158

158159
This decorator requires that the each instance supports weak references.
159160
Some immutable types and slotted classes without ``__weakref__`` as one of

Lib/functools.py

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1242,27 +1242,19 @@ def _get_or_create_cached_func(self, instance):
12421242

12431243
instance_id = id(instance)
12441244

1245-
# first try to retrieve the cached func without locking (thus avoiding any
1246-
# unnecessary contention when there is a value), but then retry
1247-
# under a lock to actually provide safety such that two parallel threads won't
1248-
# construct distinct caches simultaneously
12491245
try:
12501246
ref, cached_func = self._function_table[instance_id]
12511247
except KeyError:
1252-
with self._cache_init_lock:
1253-
try:
1254-
ref, cached_func = self._function_table[instance_id]
1255-
except KeyError:
1256-
ref = weakref.ref(
1257-
instance,
1258-
_cached_method_weakref_callback(
1259-
self._function_table, instance_id
1260-
),
1261-
)
1262-
cached_func = _wrap_unbound_cached_method(
1263-
ref, self.func, self._maxsize, self._typed
1264-
)
1265-
self._function_table[instance_id] = ref, cached_func
1248+
ref = weakref.ref(
1249+
instance,
1250+
_cached_method_weakref_callback(
1251+
self._function_table, instance_id
1252+
),
1253+
)
1254+
cached_func = _wrap_unbound_cached_method(
1255+
ref, self.func, self._maxsize, self._typed
1256+
)
1257+
self._function_table[instance_id] = ref, cached_func
12661258

12671259
return cached_func
12681260

0 commit comments

Comments
 (0)