Opened 4 years ago
Closed 4 years ago
#33099 closed Cleanup/optimization (fixed)
Improve performance of import_string().
| Reported by: | Mariusz Felisiak | Owned by: | piaoxue1949 |
|---|---|---|---|
| Component: | Utilities | Version: | 3.2 |
| Severity: | Normal | Keywords: | |
| Cc: | Triage Stage: | Accepted | |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
We can improve performance of import_string() by avoiding multiple imports for the same path. Proposed by piaoxue1949 in PR.
Change History (3)
comment:1 by , 4 years ago
| Has patch: | set |
|---|
comment:2 by , 4 years ago
Here's some back of the napkin cprofile output on my laptop, in case piaoxue1949 is unable to provide before/after based on the proposed changes:
Before, as of 46c8df640cfed5dd525ac1bcf5ad7e57b7ff2571:
In [2]: get_backends()
Out[2]:
[<django.contrib.auth.backends.ModelBackend at 0x105307e50>,
<django.contrib.auth.backends.AllowAllUsersModelBackend at 0x1053bf790>,
<django.contrib.auth.backends.RemoteUserBackend at 0x105307940>,
<django.contrib.auth.backends.AllowAllUsersRemoteUserBackend at 0x105307790>]
In [3]: %timeit get_backends()
45.2 µs ± 1.02 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [4]: %prun for _ in range(10000): get_backends()
1940003 function calls in 0.911 seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
80000 0.119 0.000 0.228 0.000 <frozen importlib._bootstrap>:166(_get_module_lock)
40000 0.118 0.000 0.718 0.000 <frozen importlib._bootstrap>:1002(_find_and_load)
80000 0.079 0.000 0.100 0.000 <frozen importlib._bootstrap>:87(acquire)
80000 0.077 0.000 0.097 0.000 <frozen importlib._bootstrap>:112(release)
80000 0.058 0.000 0.089 0.000 <frozen importlib._bootstrap>:58(__init__)
80000 0.054 0.000 0.080 0.000 <frozen importlib._bootstrap>:185(cb)
40000 0.034 0.000 0.243 0.000 <frozen importlib._bootstrap>:203(_lock_unlock_module)
40000 0.032 0.000 0.856 0.000 module_loading.py:15(import_string)
160000 0.030 0.000 0.030 0.000 {built-in method _thread.allocate_lock}
40000 0.029 0.000 0.800 0.000 __init__.py:109(import_module)
40000 0.028 0.000 0.194 0.000 <frozen importlib._bootstrap>:156(__enter__)
40000 0.024 0.000 0.761 0.000 <frozen importlib._bootstrap>:1018(_gcd_import)
... many more lines, snipped for brevity
and after, using the cached_import to peek directly into sys.modules
In [3]: %timeit get_backends()
3.78 µs ± 24.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [4]: %prun for _ in range(10000): get_backends()
260003 function calls in 0.115 seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
40000 0.024 0.000 0.061 0.000 module_loading.py:15(import_string)
10000 0.023 0.000 0.105 0.000 __init__.py:24(_get_backends)
40000 0.018 0.000 0.028 0.000 module_loading.py:8(cached_import)
40000 0.017 0.000 0.078 0.000 __init__.py:20(load_backend)
40000 0.010 0.000 0.010 0.000 {built-in method builtins.getattr}
40000 0.010 0.000 0.010 0.000 {method 'rsplit' of 'str' objects}
1 0.005 0.005 0.115 0.115 <string>:1(<module>)
40000 0.004 0.000 0.004 0.000 {method 'append' of 'list' objects}
10000 0.004 0.000 0.109 0.000 __init__.py:37(get_backends)
1 0.000 0.000 0.115 0.115 {built-in method builtins.exec}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
that's the whole list. Not stripped for brevity.
Note:
See TracTickets
for help on using tickets.
PR