Skip to content

Commit 9c0df96

Browse files
committed
gh-150818: Speed up logging.getLogger() for existing loggers
getLogger() took the logging lock on every call, including the common case of an already-registered logger. Return that logger through a lock-free fast path backed by an atomic dict lookup. First-time creation, placeholder resolution and parent/child wiring still run under the lock, and the fast path is safe under both the GIL and free threading.
1 parent 29805f0 commit 9c0df96

2 files changed

Lines changed: 12 additions & 1 deletion

File tree

Lib/logging/__init__.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1373,9 +1373,17 @@ def getLogger(self, name):
13731373
logger and fix up the parent/child references which pointed to the
13741374
placeholder to now point to the logger.
13751375
"""
1376-
rv = None
13771376
if not isinstance(name, str):
13781377
raise TypeError('A logger name must be a string')
1378+
# Fast path: an already-registered, non-placeholder logger can be
1379+
# returned without taking the lock. dict.get() is atomic under both
1380+
# the GIL and free threading, and a Logger is fully initialised before
1381+
# being inserted into loggerDict under the lock, so this never sees a
1382+
# partially-constructed object.
1383+
rv = self.loggerDict.get(name)
1384+
if rv is not None and not isinstance(rv, PlaceHolder):
1385+
return rv
1386+
rv = None
13791387
with _lock:
13801388
if name in self.loggerDict:
13811389
rv = self.loggerDict[name]
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Speed up :func:`logging.getLogger` with a lock-free fast path that returns an
2+
already-registered logger without acquiring the logging lock. Patch by Bernát
3+
Gábor.

0 commit comments

Comments
 (0)