threading --- Song song dựa trên luồng

Source code: Lib/threading.py


Mô-đun này xây dựng các giao diện phân luồng cấp cao hơn trên mô-đun _thread cấp thấp hơn.

sẵn có: not WASI.

Mô-đun này không hoạt động hoặc không có trên WebAssembly. Xem Nền tảng WebAssugging để biết thêm thông tin.

Giới thiệu

Mô-đun threading cung cấp cách chạy đồng thời nhiều threads (đơn vị nhỏ hơn của một quy trình) trong một quy trình. Nó cho phép tạo và quản lý các luồng, giúp thực hiện các tác vụ song song, chia sẻ không gian bộ nhớ. Các luồng đặc biệt hữu ích khi các tác vụ bị ràng buộc I/O, chẳng hạn như thao tác tệp hoặc thực hiện các yêu cầu mạng, trong đó phần lớn thời gian được dành để chờ đợi các tài nguyên bên ngoài.

Trường hợp sử dụng điển hình của threading bao gồm việc quản lý nhóm luồng công việc có thể xử lý đồng thời nhiều tác vụ. Đây là ví dụ cơ bản về cách tạo và bắt đầu chuỗi bằng Thread:

nhập luồng
thời gian nhập khẩu

thu thập dữ liệu def (liên kết, độ trễ = 3):
    print(f"đã bắt đầu thu thập thông tin cho {link}")
    time.sleep(delay) # Blocking I/O (mô phỏng yêu cầu mạng)
    print(f"quá trình thu thập thông tin đã kết thúc đối với {link}")

liên kết = [
    "https://python.org",
    "https://python.go-mizu.dev",
    "https://peps.python.org",
]

chủ đề # Start cho mỗi liên kết
chủ đề = []
cho liên kết trong liên kết:
    # Using `args` để truyền đối số vị trí và `kwargs` cho đối số từ khóa
    t = threading.Thread(target=crawl, args=(link,), kwargs={"delay": 2})
    chủ đề.append(t)

# Start mỗi chủ đề
cho t trong chủ đề:
    t.start()

# Wait để tất cả các chủ đề kết thúc
cho t trong chủ đề:
    t.join()

Thay đổi trong phiên bản 3.7: Mô-đun này trước đây là tùy chọn, bây giờ nó luôn có sẵn.

Xem thêm

concurrent.futures.ThreadPoolExecutor cung cấp giao diện cấp cao hơn để đẩy các tác vụ xuống luồng nền mà không chặn việc thực thi luồng gọi, trong khi vẫn có thể truy xuất kết quả của chúng khi cần.

queue cung cấp giao diện thread-safe để trao đổi dữ liệu giữa các luồng đang chạy.

asyncio cung cấp một cách tiếp cận khác để đạt được tính đồng thời ở cấp độ nhiệm vụ mà không yêu cầu sử dụng nhiều luồng hệ điều hành.

Ghi chú

Trong loạt Python 2.x, mô-đun này chứa tên camelCase cho một số phương thức và hàm. Chúng không được dùng nữa kể từ Python 3.10, nhưng chúng vẫn được hỗ trợ để tương thích với Python 2.5 trở xuống.

Trong CPython, do Global Interpreter Lock, chỉ một luồng có thể thực thi mã Python cùng một lúc (mặc dù một số thư viện hướng đến hiệu suất nhất định có thể khắc phục hạn chế này). Nếu bạn muốn ứng dụng của mình sử dụng tốt hơn tài nguyên tính toán của máy đa lõi, bạn nên sử dụng multiprocessing hoặc concurrent.futures.ProcessPoolExecutor. Tuy nhiên, phân luồng vẫn là một mô hình thích hợp nếu bạn muốn chạy đồng thời nhiều tác vụ liên quan đến I/O.

GIL và những cân nhắc về hiệu suất

Không giống như mô-đun multiprocessing, sử dụng các quy trình riêng biệt để bỏ qua global interpreter lock (GIL), mô-đun phân luồng hoạt động trong một quy trình duy nhất, nghĩa là tất cả các luồng đều chia sẻ cùng một không gian bộ nhớ. Tuy nhiên, GIL hạn chế mức tăng hiệu suất của luồng khi nói đến các tác vụ bị ràng buộc bởi CPU, vì mỗi lần chỉ có một luồng có thể thực thi mã byte Python. Mặc dù vậy, các luồng vẫn là một công cụ hữu ích để đạt được sự đồng thời trong nhiều tình huống.

Kể từ Python 3.13, các bản dựng free-threaded có thể vô hiệu hóa GIL, cho phép thực thi các luồng song song thực sự, nhưng tính năng này không có sẵn theo mặc định (xem PEP 703).

Tài liệu tham khảo

Mô-đun này xác định các chức năng sau:

threading.active_count()

Trả về số lượng đối tượng Thread hiện đang hoạt động. Số lượng trả về bằng độ dài của danh sách được trả về bởi enumerate().

Hàm activeCount là bí danh không được dùng nữa cho hàm này.

threading.current_thread()

Trả về đối tượng Thread hiện tại, tương ứng với luồng điều khiển của người gọi. Nếu luồng điều khiển của người gọi không được tạo thông qua mô-đun threading, một đối tượng luồng giả có chức năng hạn chế sẽ được trả về.

Hàm currentThread là bí danh không được dùng nữa cho hàm này.

threading.excepthook(args, /)

Xử lý ngoại lệ chưa được phát hiện bởi Thread.run().

Đối số args có các thuộc tính sau:

  • exc_type: Loại ngoại lệ.

  • exc_value: Giá trị ngoại lệ, có thể là None.

  • exc_traceback: Truy nguyên ngoại lệ, có thể là None.

  • thread: Chủ đề đưa ra ngoại lệ, có thể là None.

Nếu exc_typeSystemExit, ngoại lệ sẽ được âm thầm bỏ qua. Nếu không, ngoại lệ sẽ được in ra trên sys.stderr.

Nếu hàm này đưa ra một ngoại lệ, sys.excepthook() sẽ được gọi để xử lý nó.

threading.excepthook() có thể được ghi đè để kiểm soát cách xử lý các ngoại lệ chưa được phát hiện do Thread.run() đưa ra.

Việc lưu trữ exc_value bằng móc tùy chỉnh có thể tạo chu trình tham chiếu. Cần xóa rõ ràng để phá vỡ chu trình tham chiếu khi ngoại lệ không còn cần thiết nữa.

Việc lưu trữ thread bằng móc tùy chỉnh có thể phục hồi nó nếu nó được đặt thành một đối tượng đang được hoàn thiện. Tránh lưu trữ thread sau khi móc tùy chỉnh hoàn tất để tránh phục hồi các đối tượng.

Xem thêm

sys.excepthook() xử lý các ngoại lệ chưa được phát hiện.

Added in version 3.8.

threading.__excepthook__

Giữ giá trị ban đầu của threading.excepthook(). Nó được lưu để có thể khôi phục giá trị ban đầu trong trường hợp chúng bị thay thế bằng các vật thể bị hỏng hoặc thay thế.

Added in version 3.10.

threading.get_ident()

Trả về 'mã định danh luồng' của luồng hiện tại. Đây là một số nguyên khác 0. Giá trị của nó không có ý nghĩa trực tiếp; nó được dự định như một cookie ma thuật được sử dụng, ví dụ: để lập chỉ mục một từ điển dữ liệu theo chủ đề cụ thể. Mã nhận dạng luồng có thể được tái sử dụng khi một luồng thoát ra và một luồng khác được tạo.

Added in version 3.3.

threading.get_native_id()

Trả về ID luồng tích phân gốc của luồng hiện tại được hạt nhân gán. Đây là một số nguyên không âm. Giá trị của nó có thể được sử dụng để nhận dạng duy nhất toàn hệ thống luồng cụ thể này (cho đến khi luồng kết thúc, sau đó giá trị có thể được HĐH tái chế).

sẵn có: Windows, FreeBSD, Linux, macOS, OpenBSD, NetBSD, AIX, DragonFlyBSD, GNU/kFreeBSD.

Added in version 3.8.

Thay đổi trong phiên bản 3.13: Đã thêm hỗ trợ cho GNU/kFreeBSD.

threading.enumerate()

Trả về danh sách tất cả các đối tượng Thread hiện đang hoạt động. Danh sách này bao gồm các luồng daemon và các đối tượng luồng giả được tạo bởi current_thread(). Nó loại trừ các chủ đề đã kết thúc và các chủ đề chưa được bắt đầu. Tuy nhiên, luồng chính luôn là một phần của kết quả, ngay cả khi bị chấm dứt.

threading.main_thread()

Trả về đối tượng Thread chính. Trong điều kiện bình thường, luồng chính là luồng mà trình thông dịch Python được khởi động.

Added in version 3.4.

threading.settrace(func)

Đặt chức năng theo dõi cho tất cả các luồng bắt đầu từ mô-đun threading. func sẽ được chuyển tới sys.settrace() cho mỗi luồng, trước khi phương thức run() của nó được gọi.

threading.settrace_all_threads(func)

Đặt chức năng theo dõi cho tất cả các luồng bắt đầu từ mô-đun threading và tất cả các luồng Python hiện đang thực thi.

func sẽ được chuyển tới sys.settrace() cho mỗi luồng, trước khi phương thức run() của nó được gọi.

Added in version 3.12.

threading.gettrace()

Nhận chức năng theo dõi do settrace() thiết lập.

Added in version 3.10.

threading.setprofile(func)

Đặt chức năng cấu hình cho tất cả các luồng bắt đầu từ mô-đun threading. func sẽ được chuyển tới sys.setprofile() cho mỗi luồng, trước khi phương thức run() của nó được gọi.

threading.setprofile_all_threads(func)

Đặt chức năng cấu hình cho tất cả các luồng bắt đầu từ mô-đun threading và tất cả các luồng Python hiện đang thực thi.

func sẽ được chuyển tới sys.setprofile() cho mỗi luồng, trước khi phương thức run() của nó được gọi.

Added in version 3.12.

threading.getprofile()

Nhận chức năng hồ sơ do setprofile() thiết lập.

Added in version 3.10.

threading.stack_size([size])

Trả về kích thước ngăn xếp luồng được sử dụng khi tạo chủ đề mới. Đối số size tùy chọn chỉ định kích thước ngăn xếp sẽ được sử dụng cho các luồng được tạo sau đó và phải bằng 0 (sử dụng nền tảng hoặc mặc định được định cấu hình) hoặc giá trị nguyên dương ít nhất là 32.768 (32 KiB). Nếu size không được chỉ định thì 0 sẽ được sử dụng. Nếu việc thay đổi kích thước ngăn xếp luồng không được hỗ trợ thì RuntimeError sẽ được nâng lên. Nếu kích thước ngăn xếp được chỉ định không hợp lệ, ValueError sẽ được nâng lên và kích thước ngăn xếp không được sửa đổi. 32 KiB hiện là giá trị kích thước ngăn xếp được hỗ trợ tối thiểu để đảm bảo có đủ không gian ngăn xếp cho chính trình thông dịch. Lưu ý rằng một số nền tảng có thể có các hạn chế cụ thể về giá trị cho kích thước ngăn xếp, chẳng hạn như yêu cầu kích thước ngăn xếp tối thiểu > 32 KiB hoặc yêu cầu phân bổ theo bội số của kích thước trang bộ nhớ hệ thống - nên tham khảo tài liệu nền tảng để biết thêm thông tin (trang 4 KiB là phổ biến; sử dụng bội số của 4096 cho kích thước ngăn xếp là phương pháp được đề xuất trong trường hợp không có thông tin cụ thể hơn).

sẵn có: Windows, pthreads.

Nền tảng Unix có hỗ trợ chủ đề POSIX.

Mô-đun này cũng định nghĩa hằng số sau:

threading.TIMEOUT_MAX

Giá trị tối đa được phép cho tham số timeout của các chức năng chặn (Lock.acquire(), RLock.acquire(), Condition.wait(), v.v.). Chỉ định thời gian chờ lớn hơn giá trị này sẽ tăng OverflowError.

Added in version 3.2.

Mô-đun này định nghĩa một số lớp, được trình bày chi tiết trong các phần bên dưới.

Thiết kế của mô-đun này dựa trên mô hình phân luồng của Java. Tuy nhiên, trong đó Java tạo ra các khóa và biến điều kiện hoạt động cơ bản của mọi đối tượng thì chúng là các đối tượng riêng biệt trong Python. Lớp Thread của Python hỗ trợ một tập hợp con hành vi của lớp Thread của Java; hiện tại, không có mức độ ưu tiên, không có nhóm luồng và các luồng không thể bị hủy, dừng, tạm dừng, tiếp tục hoặc bị gián đoạn. Các phương thức tĩnh của lớp Thread của Java, khi được triển khai, sẽ được ánh xạ tới các hàm cấp mô-đun.

Tất cả các phương pháp được mô tả dưới đây đều được thực hiện nguyên tử.

Dữ liệu cục bộ

Dữ liệu cục bộ theo luồng là dữ liệu có giá trị cụ thể theo luồng. Nếu bạn có dữ liệu muốn đặt cục bộ trong một luồng, hãy tạo một đối tượng local và sử dụng các thuộc tính của nó

>>> mydata = địa phương()
>>> mydata.number = 42
>>> mydata.number
42

Bạn cũng có thể truy cập từ điển của đối tượng local:

>>> mydata.__dict__
{'số': 42}
>>> mydata.__dict__.setdefault('widget', [])
[]
>>> mydata.widgets
[]

Nếu chúng tôi truy cập dữ liệu trong một luồng khác

>>> nhật  = []
>>> giải quyết f():
... mục = đã sắp xếp(mydata.__dict__.items())
... log.append(item)
... mydata.number = 11
... log.append(mydata.number)

>>> nhập luồng
>>> thread = threading.Thread(target=f)
>>> thread.start()
>>> thread.join()
>>> nhật 
[[], 11]

chúng tôi nhận được dữ liệu khác nhau. Hơn nữa, những thay đổi được thực hiện trong luồng khác không ảnh hưởng đến dữ liệu nhìn thấy trong luồng này:

>>> mydata.number
42

Tất nhiên, các giá trị bạn nhận được từ đối tượng local, bao gồm thuộc tính __dict__ của chúng, dành cho bất kỳ luồng nào hiện tại tại thời điểm thuộc tính được đọc. Vì lý do đó, bạn thường không muốn lưu các giá trị này trên các luồng vì chúng chỉ áp dụng cho luồng mà chúng xuất phát từ đó.

Bạn có thể tạo các đối tượng local tùy chỉnh bằng cách phân lớp con local

>>> lớp MyLocal(local):
... số = 2
... def __init__(self, /, **kw):
... self.__dict__.update(kw)
... def bình phương(tự):
... trả về self.number ** 2

Điều này có thể hữu ích để hỗ trợ các giá trị, phương thức và khởi tạo mặc định. Lưu ý rằng nếu bạn xác định một phương thức __init__(), nó sẽ được gọi mỗi khi đối tượng local được sử dụng trong một luồng riêng biệt. Điều này là cần thiết để khởi tạo từ điển của mỗi luồng.

Bây giờ nếu chúng ta tạo một đối tượng local

>>> mydata = MyLocal(color='red')

chúng tôi có một số mặc định:

>>> mydata.number
2

màu ban đầu:

>>> mydata.color
'đỏ'
>>> del mydata.color

Và một phương thức hoạt động trên dữ liệu

>>> mydata.squared()
4

Như trước đây, chúng ta có thể truy cập dữ liệu trong một luồng riêng biệt:

>>> nhật  = []
>>> thread = threading.Thread(target=f)
>>> thread.start()
>>> thread.join()
>>> nhật 
[[('màu', 'đỏ')], 11]

mà không ảnh hưởng đến dữ liệu của chủ đề này:

>>> mydata.number
2
>>> mydata.color
Traceback (cuộc gọi gần đây nhất):
...
AttributionError: Đối tượng 'MyLocal' không có thuộc tính 'color'

Lưu ý rằng các lớp con có thể định nghĩa __slots__, nhưng chúng không phải là luồng cục bộ. Chúng được chia sẻ trên các chủ đề:

>>> lớp MyLocal(local):
... __slots__ = 'số'

>>> mydata = MyLocal()
>>> mydata.number = 42
>>> mydata.color = 'đỏ'

Vì vậy, chủ đề riêng biệt:

>>> thread = threading.Thread(target=f)
>>> thread.start()
>>> thread.join()

ảnh hưởng đến những gì chúng ta thấy:

>>> mydata.number
11
class threading.local

Một lớp đại diện cho dữ liệu luồng cục bộ.

Đối tượng chủ đề

Lớp Thread đại diện cho một hoạt động được chạy trong một luồng điều khiển riêng biệt. Có hai cách để chỉ định hoạt động: bằng cách chuyển một đối tượng có thể gọi đến hàm tạo hoặc bằng cách ghi đè phương thức run() trong một lớp con. Không có phương thức nào khác (ngoại trừ hàm tạo) được ghi đè trong lớp con. Nói cách khác, only ghi đè các phương thức __init__()run() của lớp này.

Khi một đối tượng luồng được tạo, hoạt động của nó phải được bắt đầu bằng cách gọi phương thức start() của luồng. Điều này gọi phương thức run() trong một luồng điều khiển riêng biệt.

Khi hoạt động của luồng được bắt đầu, luồng được coi là 'còn sống'. Nó ngừng tồn tại khi phương thức run() của nó kết thúc -- theo cách thông thường hoặc bằng cách đưa ra một ngoại lệ chưa được xử lý. Phương thức is_alive() kiểm tra xem luồng có còn hoạt động hay không.

Các luồng khác có thể gọi phương thức join() của một luồng. Điều này chặn luồng đang gọi cho đến khi luồng có phương thức join() được gọi bị chấm dứt.

Một chủ đề có một tên. Tên có thể được chuyển tới hàm tạo và đọc hoặc thay đổi thông qua thuộc tính name.

Nếu phương thức run() đưa ra một ngoại lệ, threading.excepthook() sẽ được gọi để xử lý nó. Theo mặc định, threading.excepthook() âm thầm bỏ qua SystemExit.

Một chủ đề có thể được gắn cờ là "luồng daemon". Ý nghĩa của cờ này là toàn bộ chương trình Python sẽ thoát khi chỉ còn lại các luồng daemon. Giá trị ban đầu được kế thừa từ luồng tạo. Cờ có thể được đặt thông qua thuộc tính daemon hoặc đối số hàm tạo daemon.

Ghi chú

Các luồng Daemon bị dừng đột ngột khi tắt máy. Tài nguyên của họ (chẳng hạn như tệp đang mở, giao dịch cơ sở dữ liệu, v.v.) có thể không được giải phóng đúng cách. Nếu bạn muốn các luồng của mình dừng lại một cách duyên dáng, hãy đặt chúng ở chế độ không daemon và sử dụng cơ chế báo hiệu phù hợp, chẳng hạn như Event.

Có một đối tượng "luồng chính"; điều này tương ứng với luồng điều khiển ban đầu trong chương trình Python. Nó không phải là một chủ đề daemon.

Có khả năng "đối tượng chuỗi giả" được tạo. Đây là các đối tượng luồng tương ứng với "luồng ngoài hành tinh", là các luồng điều khiển được bắt đầu bên ngoài mô-đun luồng, chẳng hạn như trực tiếp từ mã C. Các đối tượng luồng giả có chức năng hạn chế; chúng luôn được coi là còn sống và daemon và không thể là joined. Chúng không bao giờ bị xóa vì không thể phát hiện điểm cuối của các sợi ngoài hành tinh.

class threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None, context=None)

Hàm tạo này phải luôn được gọi với các đối số từ khóa. Đối số là:

group phải là None; dành riêng cho phần mở rộng trong tương lai khi lớp ThreadGroup được triển khai.

target là đối tượng có thể gọi được bằng phương thức run(). Mặc định là None, nghĩa là không có gì được gọi.

name là tên chủ đề. Theo mặc định, một tên duy nhất được tạo theo dạng "Thread-N" trong đó N là số thập phân nhỏ hoặc "Thread-N (đích)" trong đó "đích" là target.__name__ nếu đối số target được chỉ định.

args là danh sách hoặc bộ đối số cho lệnh gọi mục tiêu. Mặc định là ().

kwargs là từ điển các đối số từ khóa cho lệnh gọi mục tiêu. Mặc định là {}.

Nếu không phải là None, daemon sẽ đặt rõ ràng liệu luồng có phải là daemon hay không. Nếu None (mặc định), thuộc tính daemon được kế thừa từ luồng hiện tại.

context là giá trị Context để sử dụng khi bắt đầu chuỗi. Giá trị mặc định là None cho biết cờ sys.flags.thread_inherit_context kiểm soát hành vi. Nếu cờ đúng, các chuỗi sẽ bắt đầu bằng bản sao ngữ cảnh của người gọi start(). Nếu sai, chúng sẽ bắt đầu với một ngữ cảnh trống. Để bắt đầu rõ ràng với một ngữ cảnh trống, hãy chuyển một phiên bản mới của Context(). Để bắt đầu rõ ràng bằng bản sao của ngữ cảnh hiện tại, hãy chuyển giá trị từ copy_context(). Cờ mặc định là true trên các bản dựng có luồng tự do và ngược lại là sai.

Nếu lớp con ghi đè hàm tạo, nó phải đảm bảo gọi hàm tạo của lớp cơ sở (Thread.__init__()) trước khi thực hiện bất kỳ điều gì khác với luồng.

Thay đổi trong phiên bản 3.3: Đã thêm tham số daemon.

Thay đổi trong phiên bản 3.10: Sử dụng tên target nếu đối số name bị bỏ qua.

Thay đổi trong phiên bản 3.14: Đã thêm tham số context.

start()

Bắt đầu hoạt động của chủ đề.

Nó phải được gọi nhiều nhất một lần cho mỗi đối tượng luồng. Nó sắp xếp để phương thức run() của đối tượng được gọi trong một luồng điều khiển riêng biệt.

Phương thức này sẽ tăng RuntimeError nếu được gọi nhiều lần trên cùng một đối tượng luồng.

Nếu được hỗ trợ, hãy đặt tên luồng của hệ điều hành thành threading.Thread.name. Tên có thể bị cắt bớt tùy thuộc vào giới hạn tên luồng của hệ điều hành.

Thay đổi trong phiên bản 3.14: Đặt tên luồng của hệ điều hành.

run()

Phương thức biểu diễn hoạt động của thread.

Bạn có thể ghi đè phương thức này trong một lớp con. Phương thức run() tiêu chuẩn gọi đối tượng có thể gọi được truyền cho hàm tạo của đối tượng dưới dạng đối số target, nếu có, với các đối số vị trí và từ khóa được lấy tương ứng từ các đối số argskwargs.

Sử dụng danh sách hoặc bộ dữ liệu làm đối số args được truyền cho Thread có thể đạt được hiệu quả tương tự.

Ví dụ:

>>> từ nhập luồng Chủ đề
>>> t = Chủ đề(target=print, args=[1])
>>> t.run()
1
>>> t = Chủ đề(target=print, args=(1,))
>>> t.run()
1
join(timeout=None)

Chờ cho đến khi thread kết thúc. Điều này sẽ chặn luồng đang gọi cho đến khi luồng có phương thức join() được gọi kết thúc -- theo cách thông thường hoặc thông qua một ngoại lệ chưa được xử lý -- hoặc cho đến khi xảy ra thời gian chờ tùy chọn.

Khi đối số timeout xuất hiện chứ không phải None, nó phải là số dấu phẩy động chỉ định thời gian chờ cho thao tác tính bằng giây (hoặc phân số của nó). Vì join() luôn trả về None, bạn phải gọi is_alive() sau join() để quyết định xem có xảy ra thời gian chờ hay không -- nếu chuỗi vẫn còn hoạt động thì lệnh gọi join() đã hết thời gian chờ.

Khi không có đối số timeout hoặc None, thao tác sẽ chặn cho đến khi luồng kết thúc.

Một thread có thể được nối nhiều lần.

join() sẽ tăng RuntimeError nếu cố gắng tham gia chuỗi hiện tại vì điều đó có thể gây ra bế tắc. Đó cũng là một lỗi đối với join() một luồng trước khi nó được bắt đầu và cố gắng làm như vậy sẽ gây ra ngoại lệ tương tự.

Nếu một nỗ lực được thực hiện để tham gia một chuỗi daemon đang chạy ở giai đoạn cuối của Python finalization join() sẽ tăng PythonFinalizationError.

Thay đổi trong phiên bản 3.14: Có thể tăng PythonFinalizationError.

name

Một chuỗi chỉ được sử dụng cho mục đích nhận dạng. Nó không có ngữ nghĩa. Nhiều chủ đề có thể được đặt cùng tên. Tên ban đầu được đặt bởi hàm tạo.

Trên một số nền tảng, tên luồng được đặt ở cấp hệ điều hành khi luồng khởi động để nó hiển thị trong trình quản lý tác vụ. Tên này có thể bị cắt bớt để phù hợp với giới hạn dành riêng cho hệ thống (ví dụ: 15 byte trên Linux hoặc 63 byte trên macOS).

Các thay đổi đối với name chỉ được phản ánh ở cấp độ hệ điều hành khi chuỗi hiện đang chạy được đổi tên. (Việc đặt thuộc tính name của một luồng khác chỉ cập nhật đối tượng Python Thread.)

getName()
setName()

getter/setter API không được dùng nữa cho name; thay vào đó hãy sử dụng nó trực tiếp như một tài sản.

Sắp loại bỏ từ phiên bản 3.10.

ident

'Mã định danh luồng' của luồng này hoặc None nếu luồng chưa được bắt đầu. Đây là một số nguyên khác 0. Xem chức năng get_ident(). Mã nhận dạng luồng có thể được tái sử dụng khi một luồng thoát ra và một luồng khác được tạo. Mã định danh khả dụng ngay cả sau khi chuỗi đã thoát.

native_id

ID luồng (TID) của luồng này, do hệ điều hành (kernel) chỉ định. Đây là số nguyên không âm hoặc None nếu luồng chưa được bắt đầu. Xem chức năng get_native_id(). Giá trị này có thể được sử dụng để nhận dạng duy nhất toàn hệ thống luồng cụ thể này (cho đến khi luồng kết thúc, sau đó giá trị có thể được HĐH tái chế).

Ghi chú

Tương tự như ID tiến trình, ID luồng chỉ hợp lệ (được đảm bảo là duy nhất trên toàn hệ thống) kể từ khi luồng được tạo cho đến khi luồng bị chấm dứt.

sẵn có: Windows, FreeBSD, Linux, macOS, OpenBSD, NetBSD, AIX, DragonFlyBSD.

Added in version 3.8.

is_alive()

Trả về xem thread còn sống hay không.

Phương thức này trả về True ngay trước khi phương thức run() bắt đầu cho đến ngay sau khi phương thức run() kết thúc. Hàm mô-đun enumerate() trả về danh sách tất cả các luồng còn hoạt động.

daemon

Một giá trị boolean cho biết luồng này có phải là luồng daemon (True) hay không (False). Điều này phải được đặt trước khi start() được gọi, nếu không RuntimeError sẽ được nâng lên. Giá trị ban đầu của nó được kế thừa từ luồng tạo; luồng chính không phải là luồng daemon và do đó tất cả các luồng được tạo trong luồng chính đều mặc định là daemon = False.

Toàn bộ chương trình Python thoát khi không còn luồng không phải daemon nào còn sống.

isDaemon()
setDaemon()

getter/setter API không được dùng nữa cho daemon; thay vào đó hãy sử dụng nó trực tiếp như một tài sản.

Sắp loại bỏ từ phiên bản 3.10.

Khóa đối tượng

Khóa nguyên thủy là nguyên thủy đồng bộ hóa không thuộc sở hữu của một luồng cụ thể khi bị khóa. Trong Python, nó hiện là nguyên thủy đồng bộ hóa cấp thấp nhất hiện có, được triển khai trực tiếp bởi mô-đun mở rộng _thread.

Khóa nguyên thủy ở một trong hai trạng thái, "đã khóa" hoặc "đã mở khóa". Nó được tạo ở trạng thái mở khóa. Nó có hai phương thức cơ bản, acquire()release(). Khi trạng thái được mở khóa, acquire() sẽ chuyển trạng thái thành bị khóa và quay trở lại ngay lập tức. Khi trạng thái bị khóa, acquire() sẽ chặn cho đến khi một lệnh gọi đến release() trong một luồng khác chuyển nó thành đã mở khóa, sau đó lệnh gọi acquire() sẽ đặt lại thành bị khóa và quay trở lại. Phương thức release() chỉ nên được gọi ở trạng thái khóa; nó thay đổi trạng thái thành mở khóa và quay trở lại ngay lập tức. Nếu cố gắng mở khóa đã mở khóa, RuntimeError sẽ được nâng lên.

Khóa cũng hỗ trợ context management protocol.

Khi có nhiều hơn một luồng bị chặn trong acquire() đang chờ trạng thái chuyển sang mở khóa, chỉ một luồng tiếp tục khi lệnh gọi release() đặt lại trạng thái thành mở khóa; một trong các luồng chờ xử lý không được xác định và có thể khác nhau tùy theo quá trình triển khai.

Tất cả các phương pháp được thực hiện nguyên tử.

class threading.Lock

Lớp thực hiện các đối tượng khóa nguyên thủy. Sau khi một luồng đã có được khóa, các lần thử tiếp theo để lấy được nó sẽ bị chặn cho đến khi nó được giải phóng; bất kỳ chủ đề có thể phát hành nó.

Thay đổi trong phiên bản 3.13: Lock hiện là một lớp. Trong các Python trước đó, Lock là một hàm xuất xưởng trả về một phiên bản của loại khóa riêng tư cơ bản.

acquire(blocking=True, timeout=-1)

Có được một khóa, chặn hoặc không chặn.

Khi được gọi với đối số blocking được đặt thành True (mặc định), hãy chặn cho đến khi khóa được mở khóa, sau đó đặt thành khóa và trả về True.

Khi được gọi với đối số blocking được đặt thành False, đừng chặn. Nếu một cuộc gọi có blocking được đặt thành True sẽ bị chặn, hãy trả lại False ngay lập tức; nếu không, hãy đặt khóa thành khóa và trả về True.

Khi được gọi với đối số timeout dấu phẩy động được đặt thành giá trị dương, hãy chặn tối đa số giây được chỉ định bởi timeout và miễn là không thể lấy được khóa. Đối số timeout của -1 chỉ định thời gian chờ không giới hạn. Cấm chỉ định timeout khi blockingFalse.

Giá trị trả về là True nếu khóa được lấy thành công, False nếu không (ví dụ: nếu timeout hết hạn).

Thay đổi trong phiên bản 3.2: Thông số timeout là mới.

Thay đổi trong phiên bản 3.2: Việc thu thập khóa hiện có thể bị gián đoạn bởi các tín hiệu trên POSIX nếu việc triển khai luồng cơ bản hỗ trợ nó.

Thay đổi trong phiên bản 3.14: Việc thu thập khóa bây giờ có thể bị gián đoạn bởi các tín hiệu trên Windows.

release()

Mở khóa. Điều này có thể được gọi từ bất kỳ luồng nào, không chỉ luồng đã có khóa.

Khi khóa bị khóa, hãy đặt lại thành mở khóa và quay lại. Nếu bất kỳ luồng nào khác bị chặn khi chờ khóa được mở khóa, hãy cho phép chính xác một trong số chúng tiếp tục.

Khi được gọi trên ổ khóa đã mở khóa, RuntimeError sẽ xuất hiện.

Không có giá trị trả lại.

locked()

Trả về True nếu có được khóa.

Đối tượng RLock

Khóa reentrant là một nguyên tắc đồng bộ hóa có thể được thu thập nhiều lần bởi cùng một luồng. Trong nội bộ, nó sử dụng các khái niệm "sở hữu luồng" và "mức đệ quy" bên cạnh trạng thái khóa/mở khóa được sử dụng bởi các khóa nguyên thủy. Ở trạng thái bị khóa, một số luồng sở hữu khóa; ở trạng thái mở khóa, không có chủ đề nào sở hữu nó.

Các luồng gọi phương thức acquire() của khóa để khóa và phương thức release() để mở khóa.

Ghi chú

Khóa Reentrant hỗ trợ context management protocol, vì vậy bạn nên sử dụng with thay vì gọi acquire()release() theo cách thủ công để xử lý việc lấy và giải phóng khóa cho một khối mã.

Các cặp lệnh gọi acquire()/release() của RLock có thể được lồng nhau, không giống như acquire()/release() của Lock. Chỉ release() cuối cùng (release() của cặp ngoài cùng) mới đặt lại khóa về trạng thái mở khóa và cho phép một luồng khác bị chặn trong acquire() tiếp tục.

acquire()/release() phải được sử dụng theo cặp: mỗi lần thu được phải có một bản phát hành trong luồng đã thu được khóa. Việc không gọi giải phóng sau nhiều lần khóa đã được lấy có thể dẫn đến bế tắc.

class threading.RLock

Lớp này thực hiện các đối tượng khóa reentrant. Khóa đăng nhập lại phải được giải phóng bởi luồng đã mua nó. Sau khi một luồng đã có được khóa đăng nhập lại, thì luồng tương tự có thể lấy lại khóa đó mà không bị chặn; luồng phải giải phóng nó một lần cho mỗi lần nó có được nó.

Lưu ý rằng RLock thực sự là một hàm xuất xưởng trả về phiên bản hiệu quả nhất của lớp RLock cụ thể được nền tảng hỗ trợ.

acquire(blocking=True, timeout=-1)

Có được một khóa, chặn hoặc không chặn.

Xem thêm

Using RLock as a context manager

Được đề xuất qua các lệnh gọi acquire()release() thủ công bất cứ khi nào thực tế.

Khi được gọi với đối số blocking được đặt thành True (mặc định):

  • Nếu không có luồng nào sở hữu khóa, hãy lấy khóa và trả lại ngay lập tức.

  • Nếu một luồng khác sở hữu khóa, hãy chặn cho đến khi chúng tôi có thể lấy được khóa hoặc timeout, nếu được đặt thành giá trị float dương.

  • Nếu cùng một luồng sở hữu khóa, hãy lấy lại khóa và quay lại ngay lập tức. Đây là sự khác biệt giữa LockRLock; Lock xử lý trường hợp này giống như trường hợp trước, chặn cho đến khi lấy được khóa.

Khi được gọi với đối số blocking được đặt thành False:

  • Nếu không có luồng nào sở hữu khóa, hãy lấy khóa và trả lại ngay lập tức.

  • Nếu một chủ đề khác sở hữu khóa, hãy quay lại ngay lập tức.

  • Nếu cùng một luồng sở hữu khóa, hãy lấy lại khóa và quay lại ngay lập tức.

Trong mọi trường hợp, nếu luồng có thể lấy được khóa, hãy trả về True. Nếu luồng không thể lấy được khóa (tức là nếu không chặn hoặc đã hết thời gian chờ), hãy trả về False.

Nếu gọi nhiều lần, không gọi được release() nhiều lần có thể dẫn đến bế tắc. Hãy cân nhắc sử dụng RLock làm trình quản lý bối cảnh thay vì gọi trực tiếp việc thu thập/phát hành.

Thay đổi trong phiên bản 3.2: Thông số timeout là mới.

release()

Nhả khóa, giảm mức đệ quy. Nếu sau khi giảm nó bằng 0, hãy đặt lại khóa thành đã mở khóa (không thuộc sở hữu của bất kỳ luồng nào) và nếu bất kỳ luồng nào khác bị chặn khi chờ khóa được mở khóa, hãy cho phép chính xác một trong số chúng tiếp tục. Nếu sau khi giảm, mức đệ quy vẫn khác 0, khóa vẫn bị khóa và thuộc sở hữu của luồng gọi.

Chỉ gọi phương thức này khi luồng gọi sở hữu khóa. Một RuntimeError được nâng lên nếu phương thức này được gọi khi không lấy được khóa.

Không có giá trị trả lại.

locked()

Trả về một boolean cho biết hiện tại đối tượng này có bị khóa hay không.

Added in version 3.14.

Đối tượng điều kiện

Một biến điều kiện luôn được liên kết với một loại khóa nào đó; cái này có thể được chuyển vào hoặc một cái sẽ được tạo theo mặc định. Việc chuyển một biến vào rất hữu ích khi một số biến điều kiện phải chia sẻ cùng một khóa. Khóa là một phần của đối tượng điều kiện: bạn không cần phải theo dõi nó một cách riêng biệt.

Một biến điều kiện tuân theo context management protocol: sử dụng câu lệnh with sẽ lấy được khóa liên quan trong suốt thời gian của khối kèm theo. Các phương thức acquire()release() cũng gọi các phương thức tương ứng của khóa liên quan.

Các phương thức khác phải được gọi với khóa liên quan được giữ. Phương thức wait() giải phóng khóa và sau đó chặn cho đến khi một luồng khác đánh thức nó bằng cách gọi notify() hoặc notify_all(). Sau khi được đánh thức, wait() lấy lại được khóa và quay trở lại. Cũng có thể chỉ định thời gian chờ.

Phương thức notify() đánh thức một trong các luồng đang chờ biến điều kiện, nếu có. Phương thức notify_all() đánh thức tất cả các luồng đang chờ biến điều kiện.

Lưu ý: phương thức notify()notify_all() không nhả khóa; điều này có nghĩa là chuỗi được đánh thức sẽ không quay trở lại từ lệnh gọi wait() của chúng ngay lập tức mà chỉ khi chuỗi được gọi là notify() hoặc notify_all() cuối cùng từ bỏ quyền sở hữu khóa.

Kiểu lập trình điển hình sử dụng các biến điều kiện sử dụng khóa để đồng bộ hóa quyền truy cập vào một số trạng thái chia sẻ; các luồng quan tâm đến một thay đổi trạng thái cụ thể sẽ gọi wait() liên tục cho đến khi chúng thấy trạng thái mong muốn, trong khi các luồng sửa đổi trạng thái gọi notify() hoặc notify_all() khi chúng thay đổi trạng thái theo cách mà nó có thể là trạng thái mong muốn đối với một trong những người phục vụ. Ví dụ: đoạn mã sau đây là tình huống chung của nhà sản xuất-người tiêu dùng với dung lượng bộ đệm không giới hạn:

# Consume một mặt hàng
với cv:
    trong khi không an_item_is_available():
        cv.wait()
    get_an_available_item()

# Produce một mặt hàng
với cv:
    make_an_item_available()
    cv.notify()

Việc kiểm tra vòng lặp while để tìm điều kiện của ứng dụng là cần thiết vì wait() có thể quay trở lại sau một thời gian dài tùy ý và điều kiện nhắc lệnh gọi notify() có thể không còn đúng nữa. Điều này vốn có của lập trình đa luồng. Phương pháp wait_for() có thể được sử dụng để tự động hóa việc kiểm tra điều kiện và giảm bớt việc tính toán thời gian chờ:

# Consume một món đồ
với cv:
    cv.wait_for(an_item_is_available)
    get_an_available_item()

Để chọn giữa notify()notify_all(), hãy xem xét liệu một thay đổi trạng thái có thể chỉ thú vị đối với một hoặc một số luồng đang chờ hay không. Ví dụ. trong tình huống nhà sản xuất-người tiêu dùng điển hình, việc thêm một mục vào bộ đệm chỉ cần đánh thức một chuỗi tiêu dùng.

class threading.Condition(lock=None)

Lớp này thực hiện các đối tượng biến điều kiện. Biến điều kiện cho phép một hoặc nhiều luồng chờ cho đến khi chúng được một luồng khác thông báo.

Nếu đối số lock được đưa ra chứ không phải None, thì đối số đó phải là đối tượng Lock hoặc RLock và được sử dụng làm khóa cơ bản. Nếu không, một đối tượng RLock mới sẽ được tạo và sử dụng làm khóa cơ bản.

Thay đổi trong phiên bản 3.3: đã thay đổi từ một chức năng của nhà máy thành một lớp.

acquire(*args)

Có được khóa cơ bản. Phương thức này gọi phương thức tương ứng trên khóa cơ bản; giá trị trả về là bất cứ giá trị nào mà phương thức đó trả về.

release()

Nhả khóa bên dưới. Phương thức này gọi phương thức tương ứng trên khóa cơ bản; không có giá trị trả về.

locked()

Trả về một boolean cho biết hiện tại đối tượng này có bị khóa hay không.

Added in version 3.14.

wait(timeout=None)

Đợi cho đến khi được thông báo hoặc cho đến khi hết thời gian chờ. Nếu luồng gọi không nhận được khóa khi phương thức này được gọi, thì RuntimeError sẽ được nâng lên.

Phương thức này giải phóng khóa cơ bản, sau đó chặn cho đến khi nó được đánh thức bởi lệnh gọi notify() hoặc notify_all() cho cùng một biến điều kiện trong một luồng khác hoặc cho đến khi hết thời gian chờ tùy chọn. Sau khi được đánh thức hoặc hết thời gian chờ, nó sẽ lấy lại khóa và quay trở lại.

Khi đối số timeout xuất hiện chứ không phải None, nó phải là số dấu phẩy động chỉ định thời gian chờ cho thao tác tính bằng giây (hoặc phân số của nó).

Khi khóa cơ bản là RLock, nó không được giải phóng bằng phương pháp release(), vì điều này có thể không thực sự mở khóa khi nó được lấy đệ quy nhiều lần. Thay vào đó, một giao diện bên trong của lớp RLock được sử dụng, giao diện này thực sự mở khóa nó ngay cả khi nó được mua lại một cách đệ quy nhiều lần. Sau đó, một giao diện nội bộ khác được sử dụng để khôi phục mức đệ quy khi khóa được lấy lại.

Giá trị trả về là True trừ khi timeout đã cho hết hạn, trong trường hợp đó là False.

Thay đổi trong phiên bản 3.2: Trước đây, phương thức này luôn trả về None.

wait_for(predicate, timeout=None)

Đợi cho đến khi một điều kiện được đánh giá là đúng. predicate phải là một giá trị có thể gọi được và kết quả sẽ được hiểu là giá trị boolean. Một timeout có thể được cung cấp để có thời gian chờ đợi tối đa.

Phương thức tiện ích này có thể gọi wait() liên tục cho đến khi vị từ được thỏa mãn hoặc cho đến khi hết thời gian chờ. Giá trị trả về là giá trị trả về cuối cùng của vị từ và sẽ đánh giá thành False nếu phương thức hết thời gian chờ.

Bỏ qua tính năng hết thời gian chờ, việc gọi phương thức này gần tương đương với việc viết:

trong khi không phải  vị ngữ():
    cv.wait()

Do đó, các quy tắc tương tự được áp dụng như với wait(): Khóa phải được giữ khi được gọi và được lấy lại khi quay lại. Vị từ được đánh giá với khóa được giữ.

Added in version 3.2.

notify(n=1)

Theo mặc định, đánh thức một luồng đang chờ điều kiện này, nếu có. Nếu luồng gọi không nhận được khóa khi phương thức này được gọi, thì RuntimeError sẽ được nâng lên.

Phương thức này đánh thức tối đa n các luồng đang chờ biến điều kiện; nó sẽ không hoạt động nếu không có chủ đề nào đang chờ.

Việc triển khai hiện tại đánh thức chính xác các luồng n, nếu ít nhất các luồng n đang chờ. Tuy nhiên, không an toàn khi dựa vào hành vi này. Việc triển khai được tối ưu hóa trong tương lai đôi khi có thể đánh thức nhiều hơn các luồng n.

Lưu ý: một chuỗi đã đánh thức không thực sự quay trở lại từ lệnh gọi wait() của nó cho đến khi nó có thể lấy lại khóa. Vì notify() không mở khóa nên người gọi nó sẽ mở khóa.

notify_all()

Đánh thức tất cả các chủ đề đang chờ ở điều kiện này. Phương thức này hoạt động giống như notify(), nhưng đánh thức tất cả các luồng đang chờ thay vì một. Nếu luồng gọi không nhận được khóa khi phương thức này được gọi, thì RuntimeError sẽ được nâng lên.

Phương thức notifyAll là bí danh không được dùng nữa cho phương thức này.

Đối tượng ngữ nghĩa

Đây là một trong những nguyên tắc đồng bộ hóa lâu đời nhất trong lịch sử khoa học máy tính, được phát minh bởi nhà khoa học máy tính đầu tiên người Hà Lan Edsger W. Dijkstra (ông sử dụng tên P()V() thay vì acquire()release()).

Một semaphore quản lý một bộ đếm nội bộ được giảm dần theo mỗi lệnh gọi acquire() và tăng lên theo mỗi lệnh gọi release(). Bộ đếm không bao giờ có thể xuống dưới 0; khi acquire() thấy nó bằng 0, nó sẽ chặn, đợi cho đến khi một số luồng khác gọi release().

Semaphores cũng hỗ trợ context management protocol.

class threading.Semaphore(value=1)

Lớp này thực hiện các đối tượng semaphore. Một semaphore quản lý một bộ đếm nguyên tử biểu thị số lượng lệnh gọi release() trừ đi số lượng lệnh gọi acquire(), cộng với giá trị ban đầu. Phương thức acquire() sẽ chặn nếu cần thiết cho đến khi nó có thể quay trở lại mà không làm cho bộ đếm âm. Nếu không được cung cấp, value mặc định là 1.

Đối số tùy chọn cung cấp value ban đầu cho bộ đếm bên trong; nó mặc định là 1. Nếu value đã cho nhỏ hơn 0, ValueError sẽ được nâng lên.

Thay đổi trong phiên bản 3.3: đã thay đổi từ một chức năng của nhà máy thành một lớp.

acquire(blocking=True, timeout=None)

Có được một semaphore.

Khi được gọi mà không có đối số:

  • Nếu bộ đếm bên trong lớn hơn 0 khi nhập, hãy giảm nó đi một và trả về True ngay lập tức.

  • Nếu bộ đếm bên trong bằng 0 khi nhập, hãy chặn cho đến khi được đánh thức bởi lệnh gọi tới release(). Sau khi được đánh thức (và bộ đếm lớn hơn 0), hãy giảm bộ đếm đi 1 và trả về True. Chính xác một luồng sẽ được đánh thức sau mỗi lệnh gọi tới release(). Không nên dựa vào thứ tự đánh thức các chủ đề.

Khi được gọi với blocking được đặt thành False, đừng chặn. Nếu cuộc gọi không có đối số bị chặn, hãy trả về False ngay lập tức; nếu không, hãy thực hiện tương tự như khi được gọi không có đối số và trả về True.

Khi được gọi bằng timeout không phải None, nó sẽ chặn tối đa timeout giây. Nếu quá trình thu thập không hoàn tất thành công trong khoảng thời gian đó, hãy trả về False. Trả về True nếu không.

Thay đổi trong phiên bản 3.2: Thông số timeout là mới.

release(n=1)

Giải phóng một đèn hiệu, tăng bộ đếm bên trong lên n. Khi nó bằng 0 khi nhập và các luồng khác đang chờ nó lớn hơn 0 lần nữa, hãy đánh thức n của các luồng đó.

Thay đổi trong phiên bản 3.9: Đã thêm tham số n để giải phóng nhiều luồng đang chờ cùng một lúc.

class threading.BoundedSemaphore(value=1)

Lớp thực hiện các đối tượng semaphore giới hạn. Một semaphore giới hạn sẽ kiểm tra để đảm bảo giá trị hiện tại của nó không vượt quá giá trị ban đầu. Nếu có, ValueError sẽ được nâng lên. Trong hầu hết các trường hợp, ngữ nghĩa được sử dụng để bảo vệ các tài nguyên có dung lượng hạn chế. Nếu semaphore được phát hành quá nhiều lần thì đó là dấu hiệu của lỗi. Nếu không được cung cấp, value mặc định là 1.

Thay đổi trong phiên bản 3.3: đã thay đổi từ một chức năng của nhà máy thành một lớp.

ví dụ về Semaphore

Semaphores thường được sử dụng để bảo vệ các tài nguyên có dung lượng hạn chế, ví dụ như máy chủ cơ sở dữ liệu. Trong mọi tình huống mà kích thước của tài nguyên được cố định, bạn nên sử dụng một đèn hiệu giới hạn. Trước khi sinh ra bất kỳ luồng công việc nào, luồng chính của bạn sẽ khởi tạo semaphore:

kết nối tối đa = 5
# ...
pool_sema = BoundedSemaphore(value=maxconnections)

Sau khi được sinh ra, các luồng công việc gọi các phương thức thu thập và giải phóng của semaphore khi chúng cần kết nối với máy chủ:

với pool_sema:
    conn = connectdb()
    thử:
        # ... sử dụng kết nối ...
    cuối cùng:
        conn.close()

Việc sử dụng một semaphore giới hạn sẽ làm giảm khả năng xảy ra lỗi lập trình khiến semaphore được giải phóng nhiều hơn mức thu được sẽ không bị phát hiện.

Đối tượng sự kiện

Đây là một trong những cơ chế đơn giản nhất để giao tiếp giữa các luồng: một luồng báo hiệu một sự kiện và các luồng khác chờ đợi sự kiện đó.

Một đối tượng sự kiện quản lý một cờ nội bộ có thể được đặt thành true bằng phương thức set() và đặt lại thành false bằng phương thức clear(). Phương thức wait() chặn cho đến khi cờ đúng.

class threading.Event

Lớp thực hiện các đối tượng sự kiện. Một sự kiện quản lý một cờ có thể được đặt thành true bằng phương thức set() và đặt lại thành false bằng phương thức clear(). Phương thức wait() chặn cho đến khi cờ đúng. Cờ ban đầu là sai.

Thay đổi trong phiên bản 3.3: đã thay đổi từ một chức năng của nhà máy thành một lớp.

is_set()

Trả về True khi và chỉ khi cờ nội bộ là đúng.

Phương thức isSet là bí danh không được dùng nữa cho phương thức này.

set()

Đặt cờ nội bộ thành true. Tất cả các chủ đề đang chờ nó trở thành sự thật đều được đánh thức. Các chủ đề gọi wait() khi cờ đúng sẽ không bị chặn chút nào.

clear()

Đặt lại cờ nội bộ thành sai. Sau đó, các luồng gọi wait() sẽ chặn cho đến khi set() được gọi để đặt cờ nội bộ thành true một lần nữa.

wait(timeout=None)

Chặn miễn là cờ nội bộ là sai và thời gian chờ, nếu có, chưa hết hạn. Giá trị trả về thể hiện lý do mà phương thức chặn này trả về; True nếu quay lại vì cờ nội bộ được đặt thành đúng hoặc False nếu hết thời gian chờ và cờ nội bộ không trở thành đúng trong thời gian chờ nhất định.

Khi đối số hết thời gian chờ xuất hiện chứ không phải None, thì đó phải là số dấu phẩy động chỉ định thời gian chờ cho thao tác tính bằng giây hoặc phân số của nó.

Thay đổi trong phiên bản 3.1: Trước đây, phương thức này luôn trả về None.

Đối tượng hẹn giờ

Lớp này đại diện cho một hành động chỉ được chạy sau một khoảng thời gian nhất định --- bộ đếm thời gian. Timer là một lớp con của Thread và do đó cũng có chức năng như một ví dụ về việc tạo các chủ đề tùy chỉnh.

Bộ hẹn giờ được khởi động, giống như các luồng, bằng cách gọi phương thức Timer.start của chúng. Bộ hẹn giờ có thể được dừng (trước khi hành động của nó bắt đầu) bằng cách gọi phương thức cancel(). Khoảng thời gian mà bộ hẹn giờ sẽ đợi trước khi thực hiện hành động của nó có thể không hoàn toàn giống với khoảng thời gian do người dùng chỉ định.

Ví dụ:

chắc chắn xin chào():
    print("xin chào thế giới")

t = Hẹn giờ (30.0, xin chào)
t.start() # after 30 giây, "hello, world" sẽ được in
class threading.Timer(interval, function, args=None, kwargs=None)

Tạo bộ đếm thời gian sẽ chạy function với các đối số args và đối số từ khóa kwargs, sau khi interval giây trôi qua. Nếu argsNone (mặc định) thì danh sách trống sẽ được sử dụng. Nếu kwargsNone (mặc định) thì một lệnh trống sẽ được sử dụng.

Thay đổi trong phiên bản 3.3: đã thay đổi từ một chức năng của nhà máy thành một lớp.

cancel()

Dừng bộ hẹn giờ và hủy việc thực hiện hành động của bộ hẹn giờ. Điều này sẽ chỉ hoạt động nếu bộ đếm thời gian vẫn ở trạng thái chờ.

Vật cản

Added in version 3.2.

Lớp này cung cấp một nguyên hàm đồng bộ hóa đơn giản để sử dụng bởi một số luồng cố định cần chờ lẫn nhau. Mỗi luồng cố gắng vượt qua rào cản bằng cách gọi phương thức wait() và sẽ chặn cho đến khi tất cả các luồng thực hiện lệnh gọi wait() của chúng. Tại thời điểm này, các chủ đề được phát hành đồng thời.

Rào chắn có thể được sử dụng lại nhiều lần cho cùng một số luồng.

Ví dụ: đây là một cách đơn giản để đồng bộ hóa luồng máy khách và máy chủ

b = Rào cản(2, thời gian chờ=5)

máy chủ chắc chắn():
    start_server()
    b.đợi()
    trong khi Đúng:
        kết nối = chấp nhận_connection()
        process_server_connection(kết nối)

khách hàng chắc chắn():
    b.đợi()
    trong khi Đúng:
        kết nối = make_connection()
        process_client_connection(kết nối)
class threading.Barrier(parties, action=None, timeout=None)

Tạo một đối tượng rào cản cho số lượng chủ đề parties. Một action, khi được cung cấp, có thể được gọi bởi một trong các luồng khi chúng được phát hành. timeout là giá trị thời gian chờ mặc định nếu không có giá trị nào được chỉ định cho phương thức wait().

wait(timeout=None)

Vượt qua rào cản. Khi tất cả các chủ đề của rào cản đã gọi chức năng này, tất cả chúng đều được giải phóng đồng thời. Nếu timeout được cung cấp, nó sẽ được ưu tiên sử dụng hơn bất kỳ thứ gì được cung cấp cho hàm tạo của lớp.

Giá trị trả về là một số nguyên trong phạm vi từ 0 đến parties -- 1, khác nhau đối với mỗi luồng. Điều này có thể được sử dụng để chọn một chủ đề nhằm thực hiện một số công việc dọn phòng đặc biệt, ví dụ:

i = rào cản.wait()
nếu tôi == 0:
    # Only một chủ đề cần in cái này
    print("vượt qua rào cản")

Nếu một action được cung cấp cho hàm tạo, một trong các luồng sẽ gọi nó trước khi được phát hành. Nếu lệnh gọi này gây ra lỗi, rào cản sẽ được đưa vào trạng thái bị hỏng.

Nếu cuộc gọi hết thời gian, rào cản sẽ chuyển sang trạng thái bị hỏng.

Phương pháp này có thể đưa ra ngoại lệ BrokenBarrierError nếu rào cản bị hỏng hoặc được đặt lại trong khi một luồng đang chờ.

reset()

Đưa rào cản về trạng thái trống, mặc định. Bất kỳ chủ đề nào đang chờ trên đó sẽ nhận được ngoại lệ BrokenBarrierError.

Lưu ý rằng việc sử dụng chức năng này có thể yêu cầu một số đồng bộ hóa bên ngoài nếu có các luồng khác có trạng thái không xác định. Nếu một rào cản bị phá vỡ, tốt hơn hết là bạn nên bỏ nó đi và tạo một rào cản mới.

abort()

Đặt rào cản vào trạng thái bị phá vỡ. Điều này khiến mọi lệnh gọi đang hoạt động hoặc trong tương lai tới wait() đều không thành công với BrokenBarrierError. Ví dụ, hãy sử dụng tính năng này nếu một trong các luồng cần hủy bỏ để tránh làm ứng dụng bị bế tắc.

Có thể tốt hơn là chỉ cần tạo rào cản với giá trị timeout hợp lý để tự động bảo vệ khỏi một trong các luồng bị trục trặc.

parties

Số lượng chủ đề cần thiết để vượt qua rào cản.

n_waiting

Số lượng chủ đề hiện đang chờ trong hàng rào.

broken

Một boolean có giá trị True nếu rào cản ở trạng thái bị hỏng.

exception threading.BrokenBarrierError

Ngoại lệ này, một lớp con của RuntimeError, được đưa ra khi đối tượng Barrier bị đặt lại hoặc bị hỏng.

Sử dụng khóa, điều kiện và ngữ nghĩa trong câu lệnh with

Tất cả các đối tượng được mô-đun này cung cấp có phương thức acquirerelease đều có thể được sử dụng làm trình quản lý bối cảnh cho câu lệnh with. Phương thức acquire sẽ được gọi khi khối được nhập và release sẽ được gọi khi khối được thoát. Do đó, đoạn mã sau:

với some_lock:
    # do gì đó...

tương đương với:

some_lock.acquire()
thử:
    # do gì đó...
cuối cùng:
    some_lock.release()

Hiện tại, các đối tượng Lock, RLock, Condition, SemaphoreBoundedSemaphore có thể được sử dụng làm trình quản lý bối cảnh câu lệnh with.