Skip to content

Commit 72b4a32

Browse files
author
Thomas Kemmer
committed
Reduce number of decorator lock/unlock operations in case of cache miss.
1 parent 2252883 commit 72b4a32

File tree

2 files changed

+25
-30
lines changed

2 files changed

+25
-30
lines changed

src/cachetools/_decorators.py

+17-18
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,20 @@ def _cached_locked_info(func, cache, key, lock, info):
77
def wrapper(*args, **kwargs):
88
nonlocal hits, misses
99
k = key(*args, **kwargs)
10-
try:
11-
with lock:
10+
with lock:
11+
try:
1212
result = cache[k]
1313
hits += 1
1414
return result
15-
except KeyError:
16-
with lock:
15+
except KeyError:
1716
misses += 1
1817
v = func(*args, **kwargs)
19-
# in case of a race, prefer the item already in the cache
20-
try:
21-
with lock:
18+
with lock:
19+
try:
20+
# in case of a race, prefer the item already in the cache
2221
return cache.setdefault(k, v)
23-
except ValueError:
24-
return v # value too large
22+
except ValueError:
23+
return v # value too large
2524

2625
def cache_clear():
2726
nonlocal hits, misses
@@ -87,18 +86,18 @@ def cache_clear():
8786
def _cached_locked(func, cache, key, lock):
8887
def wrapper(*args, **kwargs):
8988
k = key(*args, **kwargs)
90-
try:
91-
with lock:
89+
with lock:
90+
try:
9291
return cache[k]
93-
except KeyError:
94-
pass # key not found
92+
except KeyError:
93+
pass # key not found
9594
v = func(*args, **kwargs)
96-
# in case of a race, prefer the item already in the cache
97-
try:
98-
with lock:
95+
with lock:
96+
try:
97+
# in case of a race, prefer the item already in the cache
9998
return cache.setdefault(k, v)
100-
except ValueError:
101-
return v # value too large
99+
except ValueError:
100+
return v # value too large
102101

103102
def cache_clear():
104103
with lock:

tests/test_cached.py

+8-12
Original file line numberDiff line numberDiff line change
@@ -165,32 +165,28 @@ def test_decorator_info(self):
165165
self.assertEqual(wrapper.cache_info(), (0, 0, 2, 0))
166166

167167
def test_decorator_lock_info(self):
168-
# hit: lock.count += 1
169-
# miss: lock.count += 3 (get, update missed, set)
170-
# info: lock.count += 1
171-
# clear: lock.count += 1
172168
cache = self.cache(2)
173169
lock = CountedLock()
174170
wrapper = cachetools.cached(cache, lock=lock, info=True)(self.func)
175171
self.assertEqual(wrapper.cache_info(), (0, 0, 2, 0))
176172
self.assertEqual(lock.count, 1)
177173
self.assertEqual(wrapper(0), 0)
178-
self.assertEqual(lock.count, 4)
174+
self.assertEqual(lock.count, 3)
179175
self.assertEqual(wrapper.cache_info(), (0, 1, 2, 1))
180-
self.assertEqual(lock.count, 5)
176+
self.assertEqual(lock.count, 4)
181177
self.assertEqual(wrapper(1), 1)
182-
self.assertEqual(lock.count, 8)
178+
self.assertEqual(lock.count, 6)
183179
self.assertEqual(wrapper.cache_info(), (0, 2, 2, 2))
184-
self.assertEqual(lock.count, 9)
180+
self.assertEqual(lock.count, 7)
185181
self.assertEqual(wrapper(0), 0)
186-
self.assertEqual(lock.count, 10)
182+
self.assertEqual(lock.count, 8)
187183
self.assertEqual(wrapper.cache_info(), (1, 2, 2, 2))
188-
self.assertEqual(lock.count, 11)
184+
self.assertEqual(lock.count, 9)
189185
wrapper.cache_clear()
190-
self.assertEqual(lock.count, 12)
186+
self.assertEqual(lock.count, 10)
191187
self.assertEqual(len(cache), 0)
192188
self.assertEqual(wrapper.cache_info(), (0, 0, 2, 0))
193-
self.assertEqual(lock.count, 13)
189+
self.assertEqual(lock.count, 11)
194190

195191
def test_zero_size_cache_decorator(self):
196192
cache = self.cache(0)

0 commit comments

Comments
 (0)