4. Mô hình thực hiện¶
4.1. Cấu trúc của một chương trình¶
Một chương trình Python được xây dựng từ các khối mã. Zz000zz là một đoạn văn bản chương trình Python được thực thi dưới dạng một đơn vị. Sau đây là các khối: mô-đun, thân hàm và định nghĩa lớp. Mỗi lệnh được gõ tương tác là một khối. Tệp tập lệnh (tệp được cung cấp dưới dạng đầu vào tiêu chuẩn cho trình thông dịch hoặc được chỉ định làm đối số dòng lệnh cho trình thông dịch) là một khối mã. Lệnh script (lệnh được chỉ định trên dòng lệnh trình thông dịch với tùy chọn -c) là một khối mã. Một mô-đun chạy dưới dạng tập lệnh cấp cao nhất (dưới dạng mô-đun __main__) từ dòng lệnh sử dụng đối số -m cũng là một khối mã. Đối số chuỗi được truyền cho các hàm dựng sẵn eval() và exec() là một khối mã.
Một khối mã được thực thi trong execution frame. Một khung chứa một số thông tin quản trị (được sử dụng để gỡ lỗi) và xác định vị trí và cách thức thực thi tiếp tục sau khi quá trình thực thi của khối mã hoàn tất.
4.2. Đặt tên và ràng buộc¶
4.2.1. Ràng buộc tên¶
Names đề cập đến các đối tượng. Tên được giới thiệu bởi các hoạt động ràng buộc tên.
Các cấu trúc sau liên kết tên:
các tham số hình thức cho các hàm,
định nghĩa lớp,
định nghĩa hàm,
biểu thức gán,
targets là số nhận dạng nếu xuất hiện trong một bài tập:
câu lệnh
import.câu lệnh
type.
Câu lệnh import có dạng from ... import * liên kết tất cả các tên được xác định trong mô-đun đã nhập, ngoại trừ những tên bắt đầu bằng dấu gạch dưới. Biểu mẫu này chỉ có thể được sử dụng ở cấp mô-đun.
Mục tiêu xuất hiện trong câu lệnh del cũng được coi là bị ràng buộc cho mục đích này (mặc dù ngữ nghĩa thực tế là hủy liên kết tên).
Mỗi câu lệnh gán hoặc nhập xuất hiện trong một khối được xác định bởi định nghĩa lớp hoặc hàm hoặc ở cấp mô-đun (khối mã cấp cao nhất).
Nếu một tên bị ràng buộc trong một khối thì đó là biến cục bộ của khối đó, trừ khi được khai báo là nonlocal hoặc global. Nếu một tên bị ràng buộc ở cấp mô-đun thì đó là một biến toàn cục. (Các biến của khối mã mô-đun là cục bộ và toàn cục.) Nếu một biến được sử dụng trong khối mã nhưng không được xác định ở đó thì đó là free variable.
Mỗi lần xuất hiện của một tên trong văn bản chương trình đều đề cập đến binding của tên đó được thiết lập theo các quy tắc phân giải tên sau đây.
4.2.2. Độ phân giải của tên¶
Zz000zz xác định khả năng hiển thị của tên trong một khối. Nếu một biến cục bộ được xác định trong một khối, phạm vi của nó sẽ bao gồm khối đó. Nếu định nghĩa xảy ra trong một khối chức năng, phạm vi sẽ mở rộng đến bất kỳ khối nào có trong khối xác định, trừ khi khối được chứa đưa ra một ràng buộc khác cho tên.
Khi một tên được sử dụng trong một khối mã, nó sẽ được giải quyết bằng phạm vi kèm theo gần nhất. Tập hợp tất cả các phạm vi như vậy hiển thị cho một khối mã được gọi là environment của khối.
Khi hoàn toàn không tìm thấy tên, ngoại lệ NameError sẽ xuất hiện. Nếu phạm vi hiện tại là phạm vi hàm và tên đề cập đến một biến cục bộ chưa được liên kết với một giá trị tại thời điểm tên được sử dụng, thì một ngoại lệ UnboundLocalError sẽ xuất hiện. UnboundLocalError là một lớp con của NameError.
Nếu thao tác liên kết tên xảy ra ở bất kỳ đâu trong khối mã, thì tất cả việc sử dụng tên trong khối đều được coi là tham chiếu đến khối hiện tại. Điều này có thể dẫn đến lỗi khi tên được sử dụng trong một khối trước khi nó bị ràng buộc. Quy tắc này là tinh tế. Python thiếu các khai báo và cho phép các hoạt động liên kết tên xảy ra ở bất kỳ đâu trong khối mã. Các biến cục bộ của một khối mã có thể được xác định bằng cách quét toàn bộ văn bản của khối để tìm các hoạt động liên kết tên. Xem the FAQ entry on UnboundLocalError để biết ví dụ.
Nếu câu lệnh global xuất hiện trong một khối, thì tất cả việc sử dụng các tên được chỉ định trong câu lệnh đều đề cập đến các ràng buộc của những tên đó trong không gian tên cấp cao nhất. Các tên được phân giải trong không gian tên cấp cao nhất bằng cách tìm kiếm không gian tên chung, tức là không gian tên của mô-đun chứa khối mã và không gian tên nội trang, không gian tên của mô-đun builtins. Không gian tên chung được tìm kiếm đầu tiên. Nếu không tìm thấy tên ở đó, không gian tên nội trang sẽ được tìm kiếm tiếp theo. Nếu tên cũng không được tìm thấy trong không gian tên nội trang, các biến mới sẽ được tạo trong không gian tên chung. Tuyên bố chung phải đi trước tất cả việc sử dụng các tên được liệt kê.
Câu lệnh global có cùng phạm vi với thao tác liên kết tên trong cùng một khối. Nếu phạm vi bao quanh gần nhất của một biến tự do chứa câu lệnh toàn cục thì biến tự do đó được coi là toàn cục.
Câu lệnh nonlocal khiến các tên tương ứng tham chiếu đến các biến bị ràng buộc trước đó trong phạm vi hàm kèm theo gần nhất. SyntaxError được nâng lên tại thời điểm biên dịch nếu tên đã cho không tồn tại trong bất kỳ phạm vi hàm kèm theo nào. Type parameters không thể phục hồi bằng câu lệnh nonlocal.
Không gian tên cho mô-đun được tạo tự động khi mô-đun được nhập lần đầu tiên. Mô-đun chính của tập lệnh luôn được gọi là __main__.
Các khối định nghĩa lớp và các đối số cho exec() và eval() là đặc biệt trong bối cảnh phân giải tên. Định nghĩa lớp là một câu lệnh thực thi có thể sử dụng và định nghĩa tên. Các tham chiếu này tuân theo các quy tắc thông thường để phân giải tên ngoại trừ các biến cục bộ không liên kết sẽ được tra cứu trong không gian tên chung. Không gian tên của định nghĩa lớp trở thành từ điển thuộc tính của lớp. Phạm vi tên được xác định trong khối lớp được giới hạn trong khối lớp; nó không mở rộng đến các khối mã của phương thức. Điều này bao gồm các phần hiểu và biểu thức trình tạo, nhưng nó không bao gồm annotation scopes, có quyền truy cập vào phạm vi lớp kèm theo của chúng. Điều này có nghĩa là những điều sau đây sẽ thất bại:
lớp A:
một = 42
b = list(a + i cho i trong phạm vi (10))
Tuy nhiên, những điều sau đây sẽ thành công:
lớp A:
gõ Bí danh = Lồng nhau
lớp lồng nhau: vượt qua
print(A.A.Alias.__value__) # <type 'A.Nested'>
4.2.3. Phạm vi chú thích¶
Các câu lệnh Annotations, type parameter lists và type giới thiệu annotation scopes, hoạt động gần giống như phạm vi hàm, nhưng có một số ngoại lệ được thảo luận bên dưới.
Phạm vi chú thích được sử dụng trong các ngữ cảnh sau:
Nhập danh sách tham số cho generic type aliases.
Nhập danh sách tham số cho generic functions. Các chú thích của hàm chung được thực thi trong phạm vi chú thích, nhưng các giá trị mặc định và trang trí của nó thì không.
Nhập danh sách tham số cho generic classes. Các lớp cơ sở và đối số từ khóa của một lớp chung được thực thi trong phạm vi chú thích, nhưng các trình trang trí của nó thì không.
Giới hạn, ràng buộc và giá trị mặc định cho tham số loại (lazily evaluated).
Giá trị của bí danh loại (lazily evaluated).
Phạm vi chú thích khác với phạm vi chức năng theo các cách sau:
Phạm vi chú thích có quyền truy cập vào không gian tên lớp kèm theo của chúng. Nếu phạm vi chú thích nằm ngay trong phạm vi lớp hoặc trong phạm vi chú thích khác nằm ngay trong phạm vi lớp, thì mã trong phạm vi chú thích có thể sử dụng các tên được xác định trong phạm vi lớp như thể nó được thực thi trực tiếp trong nội dung lớp. Điều này trái ngược với các hàm thông thường được xác định trong các lớp, không thể truy cập các tên được xác định trong phạm vi lớp.
Các biểu thức trong phạm vi chú thích không thể chứa các biểu thức
yield,yield from,awaithoặc:=. (Những biểu thức này được cho phép trong các phạm vi khác có trong phạm vi chú thích.)Tên được xác định trong phạm vi chú thích không thể được phục hồi bằng câu lệnh
nonlocaltrong phạm vi bên trong. Điều này chỉ bao gồm các tham số loại, vì không có phần tử cú pháp nào khác có thể xuất hiện trong phạm vi chú thích có thể giới thiệu tên mới.Mặc dù phạm vi chú thích có tên nội bộ, tên đó không được phản ánh trong qualified name của các đối tượng được xác định trong phạm vi. Thay vào đó,
__qualname__của các đối tượng như vậy giống như đối tượng được xác định trong phạm vi kèm theo.
Added in version 3.12: Phạm vi chú thích đã được giới thiệu trong Python 3.12 như một phần của PEP 695.
Thay đổi trong phiên bản 3.13: Phạm vi chú thích cũng được sử dụng cho các giá trị mặc định của tham số loại, như được giới thiệu bởi PEP 696.
4.2.4. Đánh giá lười biếng¶
Hầu hết phạm vi chú thích là lazily evaluated. Điều này bao gồm các chú thích, giá trị của bí danh loại được tạo thông qua câu lệnh type cũng như các giới hạn, ràng buộc và giá trị mặc định của các biến loại được tạo thông qua type parameter syntax. Điều này có nghĩa là chúng không được đánh giá khi bí danh loại hoặc biến loại được tạo hoặc khi đối tượng mang chú thích được tạo. Thay vào đó, chúng chỉ được đánh giá khi cần thiết, chẳng hạn như khi thuộc tính __value__ trên bí danh loại được truy cập.
Ví dụ:
>>> gõ Bí danh = 1/0
>>> Bí danh.__value__
Traceback (cuộc gọi gần đây nhất):
...
ZeroDivisionError: chia cho 0
>>> def func[T: 1/0](): vượt qua
>>> T = func.__type_params__[0]
>>> T.__ ràng buộc__
Traceback (cuộc gọi gần đây nhất):
...
ZeroDivisionError: chia cho 0
Ở đây, ngoại lệ chỉ được nêu ra khi thuộc tính __value__ của bí danh loại hoặc thuộc tính __bound__ của biến loại được truy cập.
Hành vi này chủ yếu hữu ích cho việc tham chiếu đến các kiểu chưa được xác định khi bí danh kiểu hoặc biến kiểu được tạo. Ví dụ: đánh giá lười biếng cho phép tạo các bí danh kiểu đệ quy lẫn nhau:
từ việc nhập nhập theo nghĩa đen
gõ SimpleExpr = int | Trong ngoặc đơn
gõ Dấu ngoặc đơn = tuple[Literal["("], Expr, Literal[")"]]
gõ Expr = SimpleExpr | tuple[SimpleExpr, Literal["+", "-"], Expr]
Các giá trị được đánh giá theo từng phần được đánh giá theo annotation scope, có nghĩa là các tên xuất hiện bên trong giá trị được đánh giá theo từng phần sẽ được tra cứu như thể chúng được sử dụng trong phạm vi kèm theo ngay lập tức.
Added in version 3.12.
4.2.5. Nội dung và thực thi hạn chế¶
Người dùng không nên chạm vào __builtins__; nó thực sự là một chi tiết thực hiện. Người dùng muốn ghi đè các giá trị trong không gian tên nội trang nên import mô-đun builtins và sửa đổi các thuộc tính của nó một cách thích hợp.
Không gian tên nội trang liên quan đến việc thực thi một khối mã thực sự được tìm thấy bằng cách tra cứu tên __builtins__ trong không gian tên chung của nó; đây phải là một từ điển hoặc một mô-đun (trong trường hợp sau, từ điển của mô-đun được sử dụng). Theo mặc định, khi ở mô-đun __main__, __builtins__ là mô-đun tích hợp builtins; khi ở bất kỳ mô-đun nào khác, __builtins__ là bí danh cho từ điển của chính mô-đun builtins.
4.2.6. Tương tác với các tính năng động¶
Việc phân giải tên của các biến tự do xảy ra trong thời gian chạy, không phải lúc biên dịch. Điều này có nghĩa là đoạn mã sau sẽ in 42:
tôi = 10
chắc chắn f():
in(i)
tôi = 42
f()
Các hàm eval() và exec() không có quyền truy cập vào môi trường đầy đủ để phân giải tên. Tên có thể được phân giải trong không gian tên cục bộ và chung của người gọi. Các biến miễn phí không được giải quyết trong không gian tên kèm theo gần nhất mà trong không gian tên chung. [1] Hàm exec() và eval() có các đối số tùy chọn để ghi đè không gian tên chung và cục bộ. Nếu chỉ có một không gian tên được chỉ định thì nó sẽ được sử dụng cho cả hai.
4.3. Ngoại lệ¶
Ngoại lệ là phương tiện thoát ra khỏi luồng điều khiển thông thường của khối mã để xử lý lỗi hoặc các điều kiện ngoại lệ khác. Một ngoại lệ là raised tại thời điểm phát hiện lỗi; nó có thể là handled bởi khối mã xung quanh hoặc bởi bất kỳ khối mã nào trực tiếp hoặc gián tiếp gọi khối mã nơi xảy ra lỗi.
Trình thông dịch Python đưa ra một ngoại lệ khi phát hiện lỗi trong thời gian chạy (chẳng hạn như chia cho 0). Một chương trình Python cũng có thể đưa ra một ngoại lệ một cách rõ ràng bằng câu lệnh raise. Trình xử lý ngoại lệ được chỉ định bằng câu lệnh try ... except. Mệnh đề finally của câu lệnh như vậy có thể được sử dụng để chỉ định mã dọn dẹp không xử lý ngoại lệ nhưng được thực thi cho dù có xảy ra ngoại lệ trong mã trước đó hay không.
Python sử dụng mô hình xử lý lỗi "chấm dứt": trình xử lý ngoại lệ có thể tìm hiểu điều gì đã xảy ra và tiếp tục thực thi ở cấp độ bên ngoài, nhưng nó không thể sửa chữa nguyên nhân gây ra lỗi và thử lại thao tác bị lỗi (ngoại trừ việc nhập lại đoạn mã vi phạm từ trên xuống).
Khi một ngoại lệ hoàn toàn không được xử lý, trình thông dịch sẽ chấm dứt việc thực thi chương trình hoặc quay lại vòng lặp chính tương tác của nó. Trong cả hai trường hợp, nó in ra dấu vết ngăn xếp, ngoại trừ khi ngoại lệ là SystemExit.
Các ngoại lệ được xác định bởi các thể hiện của lớp. Mệnh đề except được chọn tùy thuộc vào lớp của phiên bản: nó phải tham chiếu đến lớp của phiên bản đó hoặc non-virtual base class của phiên bản đó. Trình xử lý có thể nhận được cá thể này và có thể mang thông tin bổ sung về điều kiện ngoại lệ.
Ghi chú
Thông báo ngoại lệ không phải là một phần của API Python. Nội dung của chúng có thể thay đổi từ phiên bản Python này sang phiên bản tiếp theo mà không có cảnh báo và không nên dựa vào mã chạy dưới nhiều phiên bản của trình thông dịch.
Xem thêm mô tả về câu lệnh try ở phần Tuyên bố try và câu lệnh raise ở phần Tuyên bố raise.
4.4. Thành phần thời gian chạy¶
4.4.1. Mô hình tính toán tổng quát¶
Mô hình thực thi của Python không hoạt động trong chân không. Nó chạy trên máy chủ và thông qua môi trường thời gian chạy của máy chủ đó, bao gồm cả hệ điều hành (OS) của nó, nếu có. Khi một chương trình chạy, các lớp khái niệm về cách chương trình chạy trên máy chủ trông giống như sau:
host machineprocess (tài nguyên toàn cầu)thread (chạy mã máy)
Mỗi tiến trình đại diện cho một chương trình đang chạy trên máy chủ. Hãy coi mỗi quy trình như một phần dữ liệu của chương trình. Hãy coi các luồng của tiến trình là phần thực thi của chương trình. Sự khác biệt này sẽ rất quan trọng để hiểu khái niệm về thời gian chạy Python.
Quá trình, với tư cách là phần dữ liệu, là bối cảnh thực thi trong đó chương trình chạy. Nó chủ yếu bao gồm tập hợp các tài nguyên được máy chủ gán cho chương trình, bao gồm bộ nhớ, tín hiệu, thẻ điều khiển tệp, ổ cắm và biến môi trường.
Các tiến trình được cô lập và độc lập với nhau. (Điều tương tự cũng đúng đối với máy chủ.) Máy chủ quản lý quyền truy cập của quy trình vào các tài nguyên được chỉ định của nó, ngoài việc phối hợp giữa các quy trình.
Mỗi luồng thể hiện việc thực thi thực tế mã máy của chương trình, chạy tương ứng với các tài nguyên được gán cho quy trình của chương trình. Việc thực hiện đó diễn ra như thế nào và khi nào hoàn toàn phụ thuộc vào máy chủ.
Theo quan điểm của Python, một chương trình luôn bắt đầu với chính xác một luồng. Tuy nhiên, chương trình có thể phát triển để chạy trong nhiều luồng đồng thời. Không phải tất cả các máy chủ đều hỗ trợ nhiều luồng cho mỗi tiến trình, nhưng hầu hết đều hỗ trợ. Không giống như các tiến trình, các luồng trong một tiến trình không bị cô lập và độc lập với nhau. Cụ thể, tất cả các luồng trong một tiến trình đều chia sẻ tất cả tài nguyên của tiến trình đó.
Điểm cơ bản của các luồng là mỗi luồng thực hiện run một cách độc lập, cùng lúc với các luồng khác. Điều đó có thể chỉ mang tính khái niệm đồng thời ("đồng thời") hoặc về mặt vật lý ("song song"). Dù bằng cách nào, các luồng hoạt động hiệu quả ở tốc độ không đồng bộ hóa.
Ghi chú
Tốc độ không đồng bộ hóa đó có nghĩa là không có bộ nhớ nào của tiến trình được đảm bảo duy trì tính nhất quán cho mã chạy trong bất kỳ luồng nhất định nào. Do đó, các chương trình đa luồng phải quan tâm đến việc phối hợp truy cập vào các tài nguyên được chia sẻ có chủ ý. Tương tự như vậy, họ phải hết sức cẩn thận để không truy cập bất kỳ tài nguyên other nào trong nhiều luồng; nếu không, hai luồng chạy cùng lúc có thể vô tình cản trở việc sử dụng một số dữ liệu được chia sẻ của nhau. Tất cả điều này đúng cho cả chương trình Python và thời gian chạy Python.
Chi phí của yêu cầu rộng rãi, không có cấu trúc này là sự đánh đổi cho loại đồng thời thô mà các luồng cung cấp. Giải pháp thay thế cho kỷ luật bắt buộc thường có nghĩa là xử lý các lỗi không xác định và hỏng dữ liệu.
4.4.2. Mô hình thời gian chạy Python¶
Các lớp khái niệm tương tự áp dụng cho từng chương trình Python, với một số lớp dữ liệu bổ sung dành riêng cho Python:
host machineprocess (tài nguyên toàn cầu)Thời gian chạy toàn cầu của Python (state)Trình thông dịch Python (state)thread (chạy mã byte Python và "C-API")Chủ đề Python state
Ở cấp độ khái niệm: khi một chương trình Python khởi động, nó trông giống hệt như sơ đồ đó, với mỗi sơ đồ một. Thời gian chạy có thể phát triển để bao gồm nhiều trình thông dịch và mỗi trình thông dịch có thể phát triển để bao gồm nhiều trạng thái luồng.
Ghi chú
Việc triển khai Python không nhất thiết phải triển khai các lớp thời gian chạy một cách rõ ràng hoặc thậm chí cụ thể. Ngoại lệ duy nhất là những nơi mà các lớp riêng biệt được chỉ định trực tiếp hoặc hiển thị cho người dùng, chẳng hạn như thông qua mô-đun threading.
Ghi chú
Trình thông dịch ban đầu thường được gọi là trình thông dịch "chính". Một số triển khai Python, như CPython, gán các vai trò đặc biệt cho trình thông dịch chính.
Tương tự như vậy, luồng máy chủ nơi thời gian chạy được khởi tạo được gọi là luồng "chính". Nó có thể khác với luồng ban đầu của tiến trình, mặc dù chúng thường giống nhau. Trong một số trường hợp, "luồng chính" có thể còn cụ thể hơn và đề cập đến trạng thái luồng ban đầu. Thời gian chạy Python có thể gán các trách nhiệm cụ thể cho luồng chính, chẳng hạn như xử lý tín hiệu.
Nhìn chung, thời gian chạy Python bao gồm trạng thái thời gian chạy chung, trình thông dịch và trạng thái luồng. Thời gian chạy đảm bảo tất cả trạng thái đó luôn nhất quán trong suốt thời gian tồn tại của nó, đặc biệt khi được sử dụng với nhiều luồng máy chủ.
Thời gian chạy toàn cầu, ở cấp độ khái niệm, chỉ là một tập hợp các trình thông dịch. Mặc dù những trình thông dịch đó tách biệt và độc lập với nhau nhưng chúng có thể chia sẻ một số dữ liệu hoặc tài nguyên khác. Bộ thực thi chịu trách nhiệm quản lý các tài nguyên toàn cầu này một cách an toàn. Bản chất thực tế và việc quản lý các nguồn lực này phụ thuộc vào việc thực hiện cụ thể. Cuối cùng, tiện ích bên ngoài của thời gian chạy toàn cầu chỉ giới hạn ở việc quản lý trình thông dịch.
Ngược lại, "trình thông dịch" về mặt khái niệm là thứ mà chúng ta thường nghĩ là "thời gian chạy Python" (đầy đủ tính năng). Khi mã máy thực thi trong luồng máy chủ tương tác với thời gian chạy Python, nó sẽ gọi Python trong ngữ cảnh của một trình thông dịch cụ thể.
Ghi chú
Thuật ngữ "trình thông dịch" ở đây không giống với "trình thông dịch mã byte", là trình thông dịch thường xuyên chạy trong các luồng, thực thi mã Python đã biên dịch.
Trong một thế giới lý tưởng, "thời gian chạy Python" sẽ đề cập đến cái mà chúng ta hiện gọi là "trình thông dịch". Tuy nhiên, nó được gọi là "thông dịch viên" ít nhất kể từ khi được giới thiệu vào năm 1997 (CPython:a027efa5b).
Mỗi trình thông dịch đóng gói hoàn toàn tất cả trạng thái không phải toàn cục, không theo luồng cụ thể cần thiết để thời gian chạy Python hoạt động. Đáng chú ý, trạng thái của trình thông dịch vẫn tồn tại giữa các lần sử dụng. Nó bao gồm dữ liệu cơ bản như sys.modules. Thời gian chạy đảm bảo nhiều luồng sử dụng cùng một trình thông dịch sẽ chia sẻ nó một cách an toàn giữa chúng.
Việc triển khai Python có thể hỗ trợ sử dụng nhiều trình thông dịch cùng lúc trong cùng một quy trình. Họ độc lập và tách biệt với nhau. Ví dụ: mỗi trình thông dịch có sys.modules riêng.
Đối với trạng thái thời gian chạy dành riêng cho luồng, mỗi trình thông dịch có một tập hợp các trạng thái luồng mà nó quản lý, giống như cách thời gian chạy chung chứa một tập hợp các trình thông dịch. Nó có thể có trạng thái luồng cho bao nhiêu luồng máy chủ mà nó cần. Nó thậm chí có thể có nhiều trạng thái luồng cho cùng một luồng máy chủ, mặc dù điều đó không phổ biến.
Về mặt khái niệm, mỗi trạng thái luồng có tất cả dữ liệu thời gian chạy dành riêng cho luồng mà trình thông dịch cần để hoạt động trong một luồng máy chủ. Trạng thái luồng bao gồm ngoại lệ được nêu ra hiện tại và ngăn xếp cuộc gọi Python của luồng. Nó có thể bao gồm các tài nguyên dành riêng cho chủ đề khác.
Ghi chú
Thuật ngữ "luồng Python" đôi khi có thể đề cập đến trạng thái luồng, nhưng thông thường nó có nghĩa là luồng được tạo bằng mô-đun threading.
Mỗi trạng thái luồng, trong suốt thời gian tồn tại của nó, luôn được gắn với chính xác một trình thông dịch và chính xác một luồng máy chủ. Nó sẽ chỉ được sử dụng trong chuỗi đó và với trình thông dịch đó.
Nhiều trạng thái luồng có thể được gắn với cùng một luồng máy chủ, cho dù dành cho các trình thông dịch khác nhau hay thậm chí cùng một trình thông dịch. Tuy nhiên, đối với bất kỳ luồng máy chủ cụ thể nào, tại một thời điểm chỉ có một trong các trạng thái luồng được gắn với nó có thể được sử dụng bởi luồng đó.
Các trạng thái luồng được tách biệt và độc lập với nhau và không chia sẻ bất kỳ dữ liệu nào, ngoại trừ việc có thể chia sẻ trình thông dịch và các đối tượng hoặc tài nguyên khác thuộc về trình thông dịch đó.
Khi một chương trình đang chạy, các luồng Python mới có thể được tạo bằng mô-đun threading (trên các nền tảng và triển khai Python hỗ trợ các luồng). Các quy trình bổ sung có thể được tạo bằng cách sử dụng các mô-đun os, subprocess và multiprocessing. Trình thông dịch có thể được tạo và sử dụng với mô-đun interpreters. Coroutine (async) có thể được chạy bằng asyncio trong mỗi trình thông dịch, thường chỉ trong một luồng duy nhất (thường là luồng chính).
Chú thích cuối trang