42. Khóa nhập

Khóa nhập là cơ chế đồng bộ hóa giúp ngăn chặn việc nhập đồng thời không an toàn. Trong CPython, việc nhập không chỉ là tra cứu tên. Họ có thể tạo các đối tượng mô-đun, thay đổisys.modules, thực thi mã Python tùy ý, khởi tạo các mô-đun mở rộng, cập nhật thuộc tính gói, biên dịch tệp nguồn, đọc bộ đệm mã byte và chạy mã khởi tạo gói.

Nếu không khóa, hai luồng có thể nhập cùng một mô-đun cùng lúc và quan sát trạng thái mô-đun không nhất quán.

Khóa nhập tồn tại vì nhập là quá trình thực thi và quá trình thực thi sẽ thay đổi trạng thái thời gian chạy chung.

42.1 Tại sao hàng nhập khẩu cần khóa

Hãy xem xét mô-đun này:```python id="ez8v8a"

cache.py

print("initializing cache")

items = {}

def get(key): return items[key] Bây giờ hãy xem xét hai luồng thực hiện việc này cùng một lúc:python id="2pklaf" import cache Nếu không đồng bộ hóa, cả hai luồng có thể:text id="oy5qmp" create a module object insert or overwrite sys.modules["cache"] execute cache.py initialize items twice observe a partially initialized module bind different module objects


## 42.2 Nhp làm thay đổi trng thái thi gian chy toàn cu

Nhp trng thái chia s chm.

Các cu trúc chia s quan trng bao gm:```text id="yxk2bl"
sys.modules
sys.meta_path
sys.path
sys.path_hooks
sys.path_importer_cache
parent package attributes
module dictionaries
bytecode cache files
extension module state
```Điu quan trng nht là`sys.modules`.

```python id="ul20gj"
import sys

print(type(sys.modules))

sys.moduleslà một từ điển bình thường, nhưng nó là trung tâm của nhận dạng mô-đun. Nếu quá trình nhập hoặc thay thế mô-đun bị hỏng đồng thời, thời gian chạy có thể quan sát thấy các mô-đun trùng lặp hoặc các mô-đun không đầy đủ.

42.3 Mô hình tinh thần đơn giản

Việc nhập đơn giản có khóa trông như thế này:```python id="d8ycx5" def import_module(name): lock = get_import_lock_for(name)

with lock:
    if name in sys.modules:
        return sys.modules[name]

    spec = find_spec(name)
    module = module_from_spec(spec)
    sys.modules[name] = module

    try:
        spec.loader.exec_module(module)
    except Exception:
        del sys.modules[name]
        raise

    return module

Việc triển khai thực tế có nhiều trường hợp hơn, nhưng ý tưởng trung tâm là:text id="dsb489" for a given module name, only one thread should execute that module's initialization at a time


CPython hin đại s dng khóa nhp dành riêng cho mô-đun trong máy nhp. Mc đích là để tránh tun t hóa tt c các ln nhp không cn thiết trong khi vn ngăn hai lung khi to cùng mt mô-đun cùng mt lúc.

V mt khái nim:```text id="r8nrgm"
import a        locks module name "a"
import b        locks module name "b"
import a again  waits for "a" if another thread is initializing it
```Điu này mang li nhiu tính đồng thi hơn so vi mt khóa nhp toàn cu duy nht, đồng thi duy trì s an toàn cho tng danh tính mô-đun.

Khóa khóa là tên mô-đun đủ điu kin:```text id="ev5p7h"
json
json.decoder
email.message
package.submodule
```Mi tên có ranh gii đồng b hóa nhp riêng.

## 42.5 Khóa nhp so vi GIL

Khóa phiên dch toàn cu và khóa nhp gii quyết các vn đề khác nhau.

| Cơ chế | Mc đích |
|---|---|
| GIL | Bo v vic thc thi trình thông dch và nhiu thao tác đối tượng ni b |
| Khóa nhp | Ngăn chn vic khi to mô-đun đồng thi không an toàn |

GIL không loi b nhu cu khóa nhp.

Quá trình nhp mô-đun có th thc hin I/O tp, thc thi mã Python tùy ý, gii phóng GIL  dng mã gc hoc ch các hot động khác. Mt lung khác có th th nhp tương t trong khi quá trình nhp đầu tiên vn đang được tiến hành.

Khóa nhp bo v bt biến cp cao hơn:```text id="u3ib58"
one module name should not be initialized concurrently by multiple threads
```## 42.6 Nhp là được cp li

Nhp khu có th kích hot nhp khu nhiu hơn.

Ví d:```python id="4hqnm0"
# app.py
import config
import server
# server.py
import logging
import socket
```Nhập khẩu`app`nhập khẩu`server`,  nhập khẩu`server`nhập các -đun khác.

Máy khóa nhập khẩu phải hỗ trợ nhập khẩu lồng nhau.

Về mặt khái niệm:```text id="k2va9e"
import app
    lock app
    execute app.py
        import server
            lock server
            execute server.py
                import socket
                    lock socket
                    execute socket.py
```Điều này  bình thường.

Một luồng đang nhập một -đun phải được phép nhập một -đun khác trong khi -đun đầu tiên vẫn đang khởi tạo.

## 42.7 Nhập đệ quy của cùng một mô-đun

Việc nhập đệ quy của cùng một -đun  thể xảy ra thông qua nhập vòng tròn.```python id="z153co"
# a.py
import b
x = 1
# b.py
import a
y = 2
```Khi`a`nhập khẩu`b`, `b`nhập khẩu`a`, lần nhập khẩu thứ hai của`a`không nên bế tắc chờ đợi cho chính .

Đây  một  do khiến việc khóa nhập phải theo dõi quyền sở hữu  đệ quy một cách cẩn thận.

Hệ thống nhập xử  việc này bằng cách trả về -đun được khởi tạo một phần từ`sys.modules`khi thích hợp.

Điều đó ngăn chặn đệ quy  hạn  tự bế tắc, nhưng  làm lộ ra trạng thái khởi tạo một phần.

## 42.8 Mô-đun được khởi tạo một phần

Trong quá trình nhập, CPython đặt -đun vào`sys.modules`trước khi thực thi  của .

Điều này hỗ trợ nhập khẩu vòng tròn.

:```python id="4jdauu"
# a.py
import b
value = 1
```:```python id="ayh1bo"
# b.py
import a
print(a.value)
```-đun`a`tồn tại `sys.modules`trước`value`được giao.  thế`b` thể nhập khẩu`a`, Nhưng`a.value` thể chưa tồn tại.

Khóa nhập ngăn chặn hai lần khởi tạo đồng thời.  không làm cho các -đun chưa hoàn thiện trở nên hoàn chỉnh.

Các vấn đề khác nhau:

| Vấn đề | Khóa nhập  giúp ích  không? |
|---|---|
| Hai luồng khởi tạo cùng một -đun |  |
| Nhập vòng quan sát -đun chưa hoàn chỉnh | Không |
| Đổ bóng -đun | Không |
| Xấu`sys.path`đặt hàng | Không |
| Tác dụng phụ cấp cao nhất | Chỉ ngăn chặn sự trùng lặp đồng thời |

Khóa cung cấp sự an toàn cho chủ đề.  không sửa cấu trúc phụ thuộc.

## 42.9 Lệnh mua lại khóa nhập

Nhập khẩu tạo thành chuỗi phụ thuộc. Một -đun  thể giữ khóa nhập của chính  trong khi nhập -đun khác.

 dụ:```text id="m3czjg"
Thread 1:
    lock a
    import b
    wait for lock b

Thread 2:
    lock b
    import a
    wait for lock a
```Đây  một hình dạng bế tắc cổ điển.

 chế nhập khẩu của CPython bao gồm tính năng phát hiện bế tắc xung quanh các khóa -đun. Khi phát hiện vòng chờ,   thể tránh bị treo vĩnh viễn  thay vào đó xử  đường dẫn -đun được khởi tạo một phần.

Điểm thiết kế quan trọng  các khóa nhập phải xử  các biểu đồ phụ thuộc vào lại  theo chu kỳ.

## 42.10 Ví dụ nhập theo luồng

 dụ này bắt đầu một số luồng nhập cùng một -đun.```python id="2bqtk9"
# slowmod.py
import time

print("slowmod start")
time.sleep(2)
value = 42
print("slowmod end")
# main.py
import threading

def worker():
    import slowmod
    print(slowmod.value)

threads = [threading.Thread(target=worker) for _ in range(5)]

for t in threads:
    t.start()

for t in threads:
    t.join()
```Hành vi dự kiến:```text id="mq93uj"
slowmod start
slowmod end
42
42
42
42
42
```Phần thân -đun thực thi một lần. Các luồng khác đợi quá trình nhập hoàn tất, sau đó sử dụng -đun được lưu trong bộ nhớ đệm.

## 42.11 Nhập đồng thời các mô-đun khác nhau

Khóa trên mỗi -đun cho phép các -đun khác nhau được nhập đồng thời khi các -đun phụ thuộc cho phép.

Chủ đề 1:```python id="jg44xg"
import alpha
```Chủ đề 2:```python id="vyvgaf"
import beta
```Nếu như`alpha``beta`độc lập, việc nhập của chúng không cần phải chặn trên cùng một khóa -đun.

Tuy nhiên, họ vẫn  thể tranh cãi về:```text id="4h21u8"
the GIL
file-system operations
path importer caches
extension module initialization
shared package parents
custom finder state
``` thể thực hiện nhập khẩu đồng thời, nhưng nhập khẩu vẫn  một hoạt động phức tạp trên toàn cầu.

## 42.12 Gói gốc và Khóa mô-đun con

Dành cho:```python id="bbvi06"
import package.submodule
```hệ thống nhập phải tải`package`Đầu tiên.

Về mặt khái niệm:```text id="9mmvrw"
lock package
initialize package
lock package.submodule
initialize package.submodule
bind package.submodule attribute
```Nếu một số chủ đề nhập các phần tử con khác nhau của cùng một gói:```python id="rp9s87"
import package.alpha
import package.beta
```họ  thể chia sẻ bước khởi tạo gói gốc.

Sau khi khởi tạo phần tử gốc, các phần tử con  thể được xử  bằng các khóa -đun riêng của chúng, tùy theo hành vi của đường dẫn gói  công cụ tìm kiếm.

## 42.13 Khóa nhập khẩu toàn cầu trong`_imp`CPython hiển thị các chức năng khóa nhập cấp độ thấp thông qua`_imp`mô-đun.```python id="8j3c5t"
import _imp

print(_imp.lock_held())
```các`_imp`-đun bao gồm các chức năng như:```text id="iqvyee"
acquire_lock
release_lock
lock_held
```Đây  những giao diện thực hiện cấp thấp.  Python thông thường không nên sử dụng chúng để đồng bộ hóa ứng dụng.

Chúng tồn tại để nhập khẩu máy móc  khả năng tương thích.

Việc sử dụng chúng không đúng cách  thể làm bế tắc quá trình hoặc can thiệp vào hệ thống nhập.

## 42.14 Khóa nhập và Trình nhập tùy chỉnh

Trình tìm kiếm  trình tải tùy chỉnh phải cho rằng chúng  thể được gọi trong quá trình đồng bộ hóa nhập.

Người tìm kiếm nên tránh hành vi chậm, chặn hoặc quay lại khi  thể.

Một bộ nạp`exec_module`phương thức thực thi  -đun.   thể nhập các -đun khác.

Hình dạng bộ nạp  dụ:```python id="viqfze"
class Loader:
    def create_module(self, spec):
        return None

    def exec_module(self, module):
        module.value = 42
```Nếu như`exec_module`nhập các -đun khác,  tham gia vào cùng một biểu đồ khóa.

Các nhà nhập khẩu tùy chỉnh nên tránh mua các khóa không liên quan theo đơn đặt hàng không nhất quán. Nếu không, họ  thể tạo ra các bế tắc bên ngoài logic khóa nhập của CPython.

## 42.15 Khóa nhập và`sys.modules`Khóa bảo vệ phần quan trọng xung quanh việc khởi tạo mô-đun.

Các hoạt động quan trọng bao gồm:```text id="hu7f15"
checking sys.modules
creating the module
inserting the module
executing module code
removing module on failure
returning the initialized module
```Thời điểm nhạy cảm nhất  chèn trước khi thực hiện.```text id="fzh60s"
sys.modules[name] = module
exec_module(module)
```Thứ tự này hỗ trợ nhập vòng tròn, nhưng điều đó  nghĩa   khác  thể quan sát -đun trước khi quá trình thực thi kết thúc.

Khóa đảm bảo các luồng khác nhập cùng tên chờ hoàn thành thay  thực hiện lại.

## 42.16 Lỗi nhập và nhả khóa

Nếu quá trình nhập không thành công, khóa phải được giải phóng.

 dụ:```python id="3sf7se"
# broken.py
raise RuntimeError("boom")
try:
    import broken
except RuntimeError:
    pass
```Sau khi thất bại, một chủ đề khác sẽ không bị chặn mãi mãi.

Hệ thống nhập khẩu phải:```text id="rhkz4v"
release the module lock
clean up sys.modules when appropriate
propagate the exception
allow future import attempts
```Lần nhập sau  thể thử lại:```python id="36ur7b"
import broken
``` sẽ thực thi lại -đun trừ khi một đối tượng -đun bị lỗi được máy móc đặc biệt cố tình để lại.

## 42.17 Mô-đun mở rộng gốc

Các -đun mở rộng làm phức tạp việc khóa nhập.

Một -đun mở rộng  thể:```text id="bc8bib"
run native initialization code
allocate process-global state
register types
import other modules
release the GIL
use static C variables
interact with subinterpreters
```Khóa nhập ngăn chặn việc khởi tạo đồng thời cùng một tên -đun mở rộng, nhưng tác giả tiện ích mở rộng vẫn cần viết  khởi tạo một cách cẩn thận.

Khởi tạo nhiều pha hiện đại giúp các -đun mở rộng lưu trữ trạng thái trên mỗi đối tượng -đun thay  chỉ trong toàn cục C.

## 42.18 Trình thông dịch phụ

Thông dịch viên phụ thêm một chiều hướng khác.

Mỗi trình thông dịch  trạng thái từ điển -đun riêng cho nhiều -đun, nhưng các -đun mở rộng gốc vẫn  thể  trạng thái C toàn quy trình trừ khi được thiết kế khác.

Khóa nhập phải được xem xét liên quan đến trạng thái trình thông dịch  trạng thái mở rộng.

Đối với các tác giả mở rộng, điều này  nghĩa :```text id="l90pr8"
avoid mutable process-global module state
prefer per-module state
support multi-phase initialization
consider subinterpreter isolation
```Khóa nhập ngăn chặn các cuộc đua nhập đồng thời, nhưng  không tự động làm cho trạng thái -đun mở rộng bị  lập giữa các trình thông dịch.

## 42.19 Khóa nhập và tải lại`importlib.reload(module)`thực thi lại mã mô-đun.```python id="q3ox9f"
import importlib
import config

importlib.reload(config)
```Tải lại phải phối hợp với trạng thái nhập   làm thay đổi từ điển -đun hiện .

Trong quá trình tải lại,  khác vẫn  thể chứa các tham chiếu đến:```text id="8a8ikh"
the module object
old functions
old classes
old constants
old imported names
```Khóa nhập  thể ngăn chặn các hoạt động tải lại/nhập xung đột đồng thời cho tên -đun, nhưng việc tải lại vẫn phức tạp về mặt ngữ nghĩa.

Tải lại không cập nhật tất cả các tài liệu tham khảo bên ngoài.

## 42.20 Khóa nhập và hiển thị trạng thái mô-đun

Khóa nhập kiểm soát các hoạt động nhập.  không làm cho -đun toàn cầu trở thành giao dịch.

Nếu  -đun thay đổi trạng thái chung trong quá trình nhập:```python id="uwbmge"
registry = []

registry.append("phase 1")
registry.append("phase 2")
ready = True
``` liên quan đến nhập khẩu tuần hoàn  thể quan sát:```text id="spya66"
registry exists
registry contains only phase 1
ready does not exist yet
```Khóa nhập ngăn chặn việc thực thi trùng lặp đồng thời, nhưng các -đun được khởi tạo một phần vẫn hiển thị thông qua nhập vòng tròn.

## 42.21 Tránh các cuộc đua về thời gian nhập khẩu

 ứng dụng phải giảm thiểu đột biến thời gian nhập.

Thích điều này hơn:```python id="1kciks"
# service.py

class Service:
    ...

def create_service(config):
    return Service(config)
```Về điều này:```python id="5wtu0a"
# service.py

config = load_config()
service = Service(config)
service.start()
```Biểu mẫu thứ hai thực hiện công việc tại thời điểm nhập. Khó kiểm tra hơn, khó tải lại hơn  nhạy cảm hơn với đơn hàng nhập khẩu.

Công việc trong thời gian nhập khẩu thường được giới hạn  các định nghĩa  các hằng số rẻ tiền.

## 42.22 Mã cấp cao nhất an toàn

 -đun cấp cao nhất an toàn thường bao gồm:```text id="xbk1bu"
imports
constants
class definitions
function definitions
small table definitions
cheap feature detection
type aliases
``` cấp cao rủi ro hơn bao gồm:```text id="ippw6v"
network calls
database connections
thread startup
event loop startup
large file reads
global registration with side effects
process-wide configuration
monkey patching
```Khóa nhập tuần tự hóa quá trình khởi tạo, nhưng việc nhập đắt tiền hoặc  nhiều tác dụng phụ vẫn ảnh hưởng đến quá trình khởi động  hoạt động đồng thời.

## 42.23 Khóa nhập và nhập chết

"Nhập chết"  quá trình nhập chờ -đun không thể hoàn tất quá trình nhập do chu kỳ phụ thuộc hoặc khóa bên ngoài.

 dụ:```python id="jt6y2f"
# a.py
import threading
import b

lock = threading.Lock()
# b.py
import a
```Việc nhập vòng tròn đơn giản thường được xử  bằng khả năng hiển thị -đun một phần. Nhưng nếu  -đun nhận được các khóa bên ngoài, khởi động các luồng hoặc chờ các sự kiện trong quá trình nhập, thì việc tạo ra các khóa chết sẽ dễ dàng hơn nhiều.

Tránh chờ đợi trên các luồng hoặc khóa bên ngoài tại thời điểm nhập.

## 42.24 Khóa tùy chỉnh trong quá trình nhập

Đây  rủi ro:```python id="626g6o"
# registry.py
import threading

lock = threading.Lock()

with lock:
    import plugin
```Nếu như`plugin`nhập khẩu`registry` cố gắng lấy cùng một khóa, chương trình  thể bị bế tắc.

Thiết kế tốt hơn:```python id="9ez7pd"
# registry.py
import threading

lock = threading.Lock()
handlers = {}

def load_plugin(name):
    import importlib
    module = importlib.import_module(name)
    return module

def register(name, handler):
    with lock:
        handlers[name] = handler
```Giữ các khóa ứng dụng bên ngoài chu kỳ phụ thuộc nhập nếu  thể.

## 42.25 Nhập hệ thống khóa và plugin

Hệ thống plugin thường nhập -đun một cách linh hoạt.```python id="iixpre"
import importlib

def load_plugins(names):
    for name in names:
        importlib.import_module(name)
```Nếu các plugin tự đăng  tại thời điểm nhập, quá trình tải sẽ được tuần tự hóa theo tên -đun nhưng vẫn thay đổi các đăng  dùng chung.

Thiết kế plugin an toàn hơn tách biệt việc nhập  đăng :```python id="d13tr6"
def load_plugin(name):
    module = importlib.import_module(name)
    return module.setup
```Sau đó gọi thiết lập trong giai đoạn được kiểm soát:```python id="p8oelv"
for setup in setups:
    setup(registry)
```Điều này làm cho thứ tự khởi tạo trở nên  ràng.

## 42.26 Khóa nhập và hiệu suất khởi động

Khóa nhập  thể ảnh hưởng đến hiệu suất khởi động trong các chương trình theo luồng.

Nếu nhiều luồng bắt đầu  nhập các phần phụ thuộc một cách lười biếng, một số luồng  thể chặn trên cùng một lần nhập.

Một cải tiến chung  nhập các phần phụ thuộc chính trong quá trình khởi động đơn luồng:```python id="e6dmwr"
def main():
    import logging
    import database
    import server

    server.run()
```Việc khởi tạo tải trước này trước khi các luồng công việc bắt đầu.

Đối với các chương trình máy chủ, mẫu thông thường :```text id="iq8ig9"
configure process
import dependencies
initialize application
start worker threads or event loop
```Tránh làm cho các luồng công nhân khám phá  nhập các biểu đồ phụ thuộc lớn một cách độc lập.

## 42.27 Chẩn đoán sự cố khóa nhập

Các triệu chứng của sự cố khóa nhập hoặc chu trình nhập bao gồm:```text id="m5z0iy"
program hangs during import
thread dump shows imports in multiple threads
partially initialized module errors
module attributes missing only during startup
plugin loading deadlocks
reload behaves inconsistently
```Các công cụ gỡ lỗi hữu ích:```python id="1mccj7"
import sys

print(sys.modules.get("module_name"))
import _imp

print(_imp.lock_held())
```Để bị treo, hãy sử dụng kết xuất luồng.```python id="csvfsw"
import faulthandler

faulthandler.dump_traceback()
```Hoặc kích hoạt trình xử  lỗi từ dòng lệnh:```bash id="7wjpm2"
python -X faulthandler app.py
```## 42.28 Thời gian nhập và tranh chấp khóa

Thời gian nhập  thể được kiểm tra bằng:```bash id="gr9wta"
python -X importtime -c "import your_package"
```Báo cáo này báo cáo thời gian được sử dụng trong quá trình nhập.

 không trực tiếp hiển thị sự tranh chấp khóa, nhưng  giúp xác định việc nhập chậm  thể trở thành điểm tranh chấp.

Nhập khẩu chậm thường đáng được chú ý khi chúng xảy ra:```text id="7c79oz"
inside worker startup
inside request paths
inside plugin discovery
inside command-line entry points
inside test collection
```## 42.29 Khóa nhập và mã không đồng bộ

 không đồng bộ không làm cho quá trình nhập không đồng bộ.

Một câu lệnh nhập khẩu bên trong một`async def`vẫn chạy đồng bộ khi phần coroutine đó thực thi.```python id="fg7lak"
async def handler():
    import heavy_module
    return heavy_module.run()
```Cuộc gọi đầu tiên đến`handler`đạt đến quá trình nhập  thể chặn vòng lặp sự kiện trong khi tải -đun.

Đối với các máy chủ không đồng bộ, hãy nhập các phần phụ thuộc nặng nề trước khi bắt đầu vòng lặp sự kiện hoặc di chuyển quá trình khởi tạo tốn kém vào các hook khởi động không đồng bộ  ràng.

## 42.30 Khóa nhập và đa xử lý

Mỗi quy trình  trạng thái trình thông dịch  trạng thái nhập riêng.

Với đa xử , các tiến trình con sẽ nhập các -đun riêng biệt.

Điều này quan trọng hơn trên các nền tảng hoặc các phương thức bắt đầu tạo ra các trình thông dịch mới.

 dụ: với việc tạo quy trình kiểu sinh sản, quy trình con sẽ nhập -đun chính.

Đây   do tại sao  đa xử  cần:```python id="w0j45j"
if __name__ == "__main__":
    main()
```Nếu không  bộ bảo vệ, các tiến trình con  thể chạy lại  cấp cao nhất trong quá trình nhập.

Khóa nhập chỉ bảo vệ nhập trong một quy trình.  không đồng bộ hóa việc nhập khẩu giữa các quy trình.

## 42.31 Khóa nhập và ghi bộ đệm bytecode

Khi CPython nhập -đun nguồn,   thể đọc hoặc ghi`.pyc`tập tin.

Mặt khác, việc nhập đồng thời  thể chạy đua xung quanh việc tạo bộ nhớ đệm  byte.

Máy móc nhập khẩu xử  việc này một cách cẩn thận. Tuy nhiên, bộ đệm  byte  một sự tối ưu hóa chứ không phải  nguồn nhận dạng -đun.

Nguồn nhận dạng :```text id="ka9zk4"
module name in sys.modules
```Bộ đệm  byte chỉ lưu trữ các đối tượng  đã biên dịch để nhập sau này nhanh hơn.

## 42.32 Khóa nhập và thay đổi hệ thống tập tin

Khóa nhập không làm cho trạng thái hệ thống tập tin ổn định.

Nếu các tệp được tạo, xóa hoặc thay thế trong khi quá trình nhập đang diễn ra, hành vi vẫn  thể gây nhầm lẫn.

 dụ:```text id="50enmw"
deployment replacing package files during process startup
tests generating modules dynamically
plugin files being written while discovery runs
zip archive changed while importing
```Sử dụng các phương pháp triển khai ổn định. Tránh thay đổi   thể nhập trong khi quá trình đang chạy đang nhập  đó.

## 42.33 Khóa nhập không phải là khóa ứng dụng

Không sử dụng nhập làm  chế đồng bộ hóa.

Đây  một  hình kém:```python id="xdy9zr"
def initialize_once():
    import initialize_side_effects
``` dựa vào bộ nhớ đệm nhập để chạy khởi tạo một lần.

Thích khởi tạo một lần  ràng:```python id="q7vhsy"
_lock = threading.Lock()
_initialized = False

def initialize_once():
    global _initialized

    if _initialized:
        return

    with _lock:
        if _initialized:
            return
        do_initialization()
        _initialized = True
```Bộ nhớ đệm nhập dành cho các -đun. Vòng đời ứng dụng phải  ràng.

## 42.34 Quy tắc thiết kế: Nhập khẩu nên nhàm chán

Nhập khẩu an toàn nhất  nhàm chán.

Một nhập khẩu nhàm chán:```text id="tjyc8p"
defines names
sets constants
imports dependencies
does no external work
finishes quickly
```Một nhập khẩu đáng ngạc nhiên:```text id="8vcz4t"
starts threads
opens sockets
loads large models
registers global plugins
patches builtins
changes logging globally
reads mutable external config
```Khóa nhập khẩu  thể làm cho việc nhập khẩu đáng ngạc nhiên trở nên ít hấp dẫn hơn.  không thể làm cho họ dễ dàng  luận.

## 42.35 Mô hình khóa nhập tối thiểu

Một  hình nhỏ gọn:```text id="iwck6e"
Thread imports module M.
Import system acquires lock for M.
If M is already initialized, return it.
If M is initializing in another thread, wait.
If this thread is already involved in the cycle, use partial module state.
Create and cache M before execution.
Execute M.
On success, mark M initialized and release lock.
On failure, clean up and release lock.
``` hình này giải thích tại sao quá trình nhập đủ an toàn theo luồng để sử dụng thông thường, tại sao quá trình nhập tuần hoàn vẫn  thể hiển thị các -đun chưa hoàn thiện  tại sao tác dụng phụ của thời gian nhập vẫn nguy hiểm.

## 42,36 Điểm mấu chốt

Khóa nhập ngăn chặn việc khởi tạo đồng thời cùng tên -đun.

Khóa bảo vệ việc tải -đun chứ không phải ngữ nghĩa -đun tùy ý.

GIL  khóa nhập giải quyết các vấn đề khác nhau.

Quá trình nhập được thực hiện lại  các -đun  thể nhập các -đun khác trong quá trình thực thi.

Việc nhập vòng tròn được xử  bằng cách chèn các -đun vào`sys.modules`trước khi thực thi, điều này  thể làm lộ ra các -đun được khởi tạo một phần.

Các trình nhập tùy chỉnh, plugin, -đun mở rộng, trình thông dịch phụ, tải lại  khởi động theo luồng đều khiến việc khóa nhập trở nên quan trọng hơn.

Thiết kế ứng dụng tốt giúp nhập dữ liệu nhanh chóng, xác định  hầu như không  tác dụng phụ bên ngoài.