Skip to content

Commit

Permalink
pythongh-117983: Defer import of threading for lazy module loading (p…
Browse files Browse the repository at this point in the history
…ythonGH-120233)

As noted in pythongh-117983, the import importlib.util can be triggered at
interpreter startup under some circumstances, so adding threading makes
it a potentially obligatory load.
Lazy loading is not used in the stdlib, so this removes an unnecessary
load for the majority of users and slightly increases the cost of the
first lazily loaded module.

An obligatory threading load breaks gevent, which monkeypatches the
stdlib. Although unsupported, there doesn't seem to be an offsetting
benefit to breaking their use case.

For reference, here are benchmarks for the current main branch:

```
❯ hyperfine -w 8 './python -c "import importlib.util"'
Benchmark 1: ./python -c "import importlib.util"
  Time (mean ± σ):       9.7 ms ±   0.7 ms    [User: 7.7 ms, System: 1.8 ms]
  Range (min … max):     8.4 ms …  13.1 ms    313 runs
```

And with this patch:

```
❯ hyperfine -w 8 './python -c "import importlib.util"'
Benchmark 1: ./python -c "import importlib.util"
  Time (mean ± σ):       8.4 ms ±   0.7 ms    [User: 6.8 ms, System: 1.4 ms]
  Range (min … max):     7.2 ms …  11.7 ms    352 runs
```

Compare to:

```
❯ hyperfine -w 8 './python -c pass'
Benchmark 1: ./python -c pass
  Time (mean ± σ):       7.6 ms ±   0.6 ms    [User: 5.9 ms, System: 1.6 ms]
  Range (min … max):     6.7 ms …  11.3 ms    390 runs
```

This roughly halves the import time of importlib.util.
(cherry picked from commit 94f50f8)

Co-authored-by: Chris Markiewicz <effigies@gmail.com>
  • Loading branch information
effigies authored and miss-islington committed Jul 3, 2024
1 parent e7008d7 commit 2a1d469
Show file tree
Hide file tree
Showing 2 changed files with 5 additions and 1 deletion.
4 changes: 3 additions & 1 deletion Lib/importlib/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

import _imp
import sys
import threading
import types


Expand Down Expand Up @@ -257,6 +256,9 @@ def create_module(self, spec):

def exec_module(self, module):
"""Make the module load lazily."""
# Threading is only needed for lazy loading, and importlib.util can
# be pulled in at interpreter startup, so defer until needed.
import threading
module.__spec__.loader = self.loader
module.__loader__ = self.loader
# Don't need to worry about deep-copying as trying to set an attribute
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Defer the ``threading`` import in ``importlib.util`` until lazy loading is
used.

0 comments on commit 2a1d469

Please sign in to comment.