Skip to content

Commit 03648a2

Browse files
authored
bpo-43392: Optimize repeated calls to __import__() (GH-24735)
Implements a two steps check in `importlib._bootstrap._find_and_load()` to avoid locking when the module has been already imported and it's ready. --- Using `importlib.__import__()`, after this, does show a big difference: Before: ``` $ ./python -c 'import timeit; print(timeit.timeit("__import__(\"timeit\")", setup="from importlib import __import__"))' 15.92248619502061 ``` After: ``` $ ./python -c 'import timeit; print(timeit.timeit("__import__(\"timeit\")", setup="from importlib import __import__"))' 1.206068897008663 ``` ---
1 parent 953d272 commit 03648a2

File tree

3 files changed

+539
-517
lines changed

3 files changed

+539
-517
lines changed

Lib/importlib/_bootstrap.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,17 +1032,28 @@ def _find_and_load_unlocked(name, import_):
10321032

10331033
def _find_and_load(name, import_):
10341034
"""Find and load the module."""
1035-
with _ModuleLockManager(name):
1036-
module = sys.modules.get(name, _NEEDS_LOADING)
1037-
if module is _NEEDS_LOADING:
1038-
return _find_and_load_unlocked(name, import_)
1035+
1036+
# Optimization: we avoid unneeded module locking if the module
1037+
# already exists in sys.modules and is fully initialized.
1038+
module = sys.modules.get(name, _NEEDS_LOADING)
1039+
if (module is _NEEDS_LOADING or
1040+
getattr(getattr(module, "__spec__", None), "_initializing", False)):
1041+
with _ModuleLockManager(name):
1042+
module = sys.modules.get(name, _NEEDS_LOADING)
1043+
if module is _NEEDS_LOADING:
1044+
return _find_and_load_unlocked(name, import_)
1045+
1046+
# Optimization: only call _bootstrap._lock_unlock_module() if
1047+
# module.__spec__._initializing is True.
1048+
# NOTE: because of this, initializing must be set *before*
1049+
# putting the new module in sys.modules.
1050+
_lock_unlock_module(name)
10391051

10401052
if module is None:
10411053
message = ('import of {} halted; '
10421054
'None in sys.modules'.format(name))
10431055
raise ModuleNotFoundError(message, name=name)
10441056

1045-
_lock_unlock_module(name)
10461057
return module
10471058

10481059

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
:func:`importlib._bootstrap._find_and_load` now implements a two-step
2+
check to avoid locking when modules have been already imported and are
3+
ready. This improves performance of repeated calls to
4+
:func:`importlib.import_module` and :func:`importlib.__import__`.

0 commit comments

Comments
 (0)