mirror of
				https://github.com/python/cpython.git
				synced 2025-10-30 21:21:22 +00:00 
			
		
		
		
	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
```
---
			
			
This commit is contained in:
		
							parent
							
								
									953d27261e
								
							
						
					
					
						commit
						03648a2a91
					
				
					 3 changed files with 539 additions and 517 deletions
				
			
		|  | @ -1032,17 +1032,28 @@ def _find_and_load_unlocked(name, import_): | ||||||
| 
 | 
 | ||||||
| def _find_and_load(name, import_): | def _find_and_load(name, import_): | ||||||
|     """Find and load the module.""" |     """Find and load the module.""" | ||||||
|     with _ModuleLockManager(name): | 
 | ||||||
|         module = sys.modules.get(name, _NEEDS_LOADING) |     # Optimization: we avoid unneeded module locking if the module | ||||||
|         if module is _NEEDS_LOADING: |     # already exists in sys.modules and is fully initialized. | ||||||
|             return _find_and_load_unlocked(name, import_) |     module = sys.modules.get(name, _NEEDS_LOADING) | ||||||
|  |     if (module is _NEEDS_LOADING or | ||||||
|  |         getattr(getattr(module, "__spec__", None), "_initializing", False)): | ||||||
|  |         with _ModuleLockManager(name): | ||||||
|  |             module = sys.modules.get(name, _NEEDS_LOADING) | ||||||
|  |             if module is _NEEDS_LOADING: | ||||||
|  |                 return _find_and_load_unlocked(name, import_) | ||||||
|  | 
 | ||||||
|  |         # Optimization: only call _bootstrap._lock_unlock_module() if | ||||||
|  |         # module.__spec__._initializing is True. | ||||||
|  |         # NOTE: because of this, initializing must be set *before* | ||||||
|  |         # putting the new module in sys.modules. | ||||||
|  |         _lock_unlock_module(name) | ||||||
| 
 | 
 | ||||||
|     if module is None: |     if module is None: | ||||||
|         message = ('import of {} halted; ' |         message = ('import of {} halted; ' | ||||||
|                    'None in sys.modules'.format(name)) |                    'None in sys.modules'.format(name)) | ||||||
|         raise ModuleNotFoundError(message, name=name) |         raise ModuleNotFoundError(message, name=name) | ||||||
| 
 | 
 | ||||||
|     _lock_unlock_module(name) |  | ||||||
|     return module |     return module | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -0,0 +1,4 @@ | ||||||
|  | :func:`importlib._bootstrap._find_and_load` now implements a two-step | ||||||
|  | check to avoid locking when modules have been already imported and are | ||||||
|  | ready. This improves performance of repeated calls to | ||||||
|  | :func:`importlib.import_module` and :func:`importlib.__import__`. | ||||||
							
								
								
									
										1031
									
								
								Python/importlib.h
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										1031
									
								
								Python/importlib.h
									
										
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Germán Méndez Bravo
						Germán Méndez Bravo