queue --- Một lớp hàng đợi được đồng bộ hóa

Source code: Lib/queue.py


Mô-đun queue triển khai hàng đợi nhiều nhà sản xuất, nhiều người tiêu dùng. Nó đặc biệt hữu ích trong lập trình luồng khi thông tin phải được trao đổi một cách an toàn giữa nhiều luồng. Lớp Queue trong mô-đun này triển khai tất cả ngữ nghĩa khóa cần thiết.

Mô-đun này triển khai ba loại hàng đợi, chỉ khác nhau ở thứ tự truy xuất các mục. Trong hàng đợi FIFO, tác vụ đầu tiên được thêm vào sẽ là tác vụ được truy xuất đầu tiên. Trong hàng đợi LIFO, mục được thêm gần đây nhất là mục được truy xuất đầu tiên (hoạt động giống như một ngăn xếp). Với hàng đợi ưu tiên, các mục nhập sẽ được sắp xếp (sử dụng mô-đun heapq) và mục nhập có giá trị thấp nhất sẽ được truy xuất trước tiên.

Trong nội bộ, ba loại hàng đợi đó sử dụng khóa để tạm thời chặn các luồng cạnh tranh; tuy nhiên, chúng không được thiết kế để xử lý việc đăng nhập lại trong một luồng.

Ngoài ra, mô-đun này còn triển khai một loại hàng đợi FIFO "đơn giản", SimpleQueue, việc triển khai cụ thể của nó sẽ cung cấp các đảm bảo bổ sung để đổi lấy chức năng nhỏ hơn.

Mô-đun queue xác định các lớp và ngoại lệ sau:

class queue.Queue(maxsize=0)

Trình xây dựng cho hàng đợi FIFO. maxsize là một số nguyên đặt giới hạn trên cho số lượng mục có thể được đặt trong hàng đợi. Quá trình chèn sẽ chặn khi đạt đến kích thước này cho đến khi các mục trong hàng đợi được sử dụng hết. Nếu maxsize nhỏ hơn hoặc bằng 0 thì kích thước hàng đợi là vô hạn.

class queue.LifoQueue(maxsize=0)

Trình xây dựng cho hàng đợi LIFO. maxsize là một số nguyên đặt giới hạn trên cho số lượng mục có thể được đặt trong hàng đợi. Quá trình chèn sẽ chặn khi đạt đến kích thước này cho đến khi các mục trong hàng đợi được sử dụng hết. Nếu maxsize nhỏ hơn hoặc bằng 0 thì kích thước hàng đợi là vô hạn.

class queue.PriorityQueue(maxsize=0)

Trình xây dựng cho hàng đợi ưu tiên. maxsize là một số nguyên đặt giới hạn trên cho số lượng mục có thể được đặt trong hàng đợi. Quá trình chèn sẽ chặn khi đạt đến kích thước này cho đến khi các mục trong hàng đợi được sử dụng hết. Nếu maxsize nhỏ hơn hoặc bằng 0 thì kích thước hàng đợi là vô hạn.

Các mục có giá trị thấp nhất sẽ được truy xuất trước (mục có giá trị thấp nhất là mục sẽ được min(entries) trả về). Mẫu điển hình cho các mục là một bộ dữ liệu có dạng: (priority_number, data).

Nếu các phần tử data không thể so sánh được thì dữ liệu có thể được gói trong một lớp bỏ qua mục dữ liệu và chỉ so sánh số ưu tiên:

từ các lớp dữ liệu nhập lớp dữ liệu, trường
từ việc nhập nhập Bất kỳ

@dataclass(thứ tự=True)
lớp Ưu tiên:
    mức độ ưu tiên: int
    mục: Any=field(so sánh=False)
class queue.SimpleQueue

Trình xây dựng cho hàng đợi FIFO không giới hạn. Hàng đợi đơn giản thiếu chức năng nâng cao như theo dõi tác vụ.

Added in version 3.7.

exception queue.Empty

Ngoại lệ nảy sinh khi get() (hoặc get_nowait()) không chặn được gọi trên đối tượng Queue trống.

exception queue.Full

Ngoại lệ nảy sinh khi gọi put() (hoặc put_nowait()) không chặn trên đối tượng Queue đã đầy.

exception queue.ShutDown

Ngoại lệ xuất hiện khi put() hoặc get() được gọi trên đối tượng Queue đã bị tắt.

Added in version 3.13.

Đối tượng xếp hàng

Các đối tượng xếp hàng (Queue, LifoQueue hoặc PriorityQueue) cung cấp các phương thức công khai được mô tả bên dưới.

Queue.qsize()

Trả về kích thước gần đúng của hàng đợi. Lưu ý, qsize() > 0 không đảm bảo rằng get() tiếp theo sẽ không chặn, qsize() < maxsize cũng không đảm bảo rằng put() sẽ không chặn.

Queue.empty()

Trả về True nếu hàng đợi trống, False nếu không. Nếu trống() trả về True, điều đó không đảm bảo rằng lệnh gọi tiếp theo tới put() sẽ không bị chặn. Tương tự, nếu void() trả về False thì điều đó không đảm bảo rằng lệnh gọi get() tiếp theo sẽ không bị chặn.

Queue.full()

Trả về True nếu hàng đợi đầy, nếu không thì trả về False. Nếu full() trả về True thì điều đó không đảm bảo rằng lệnh gọi get() tiếp theo sẽ không bị chặn. Tương tự, nếu full() trả về False thì điều đó không đảm bảo rằng lệnh gọi put() tiếp theo sẽ không bị chặn.

Queue.put(item, block=True, timeout=None)

Đặt item vào hàng đợi. Nếu các đối số tùy chọn block là đúng và timeoutNone (mặc định), hãy chặn nếu cần cho đến khi có chỗ trống. Nếu timeout là số dương, nó sẽ chặn tối đa timeout giây và tăng ngoại lệ Full nếu không có chỗ trống nào trong thời gian đó. Ngược lại (block là sai), hãy đặt một mục vào hàng đợi nếu ngay lập tức có một vị trí trống, nếu không thì sẽ đưa ra ngoại lệ Full (timeout bị bỏ qua trong trường hợp đó).

Tăng ShutDown nếu hàng đợi đã bị tắt.

Queue.put_nowait(item)

Tương đương với put(item, block=False).

Queue.get(block=True, timeout=None)

Xóa và trả lại một mục từ hàng đợi. Nếu các đối số tùy chọn block là đúng và timeoutNone (mặc định), hãy chặn nếu cần thiết cho đến khi có một mục. Nếu timeout là số dương, nó sẽ chặn tối đa timeout giây và tăng ngoại lệ Empty nếu không có mục nào có sẵn trong thời gian đó. Nếu không (block là sai), hãy trả lại một mục nếu có sẵn ngay lập tức, nếu không thì đưa ra ngoại lệ Empty (timeout bị bỏ qua trong trường hợp đó).

Trước phiên bản 3.0 trên hệ thống POSIX và đối với tất cả các phiên bản trên Windows, nếu block là đúng và timeoutNone thì thao tác này sẽ chuyển sang chế độ chờ liên tục trên khóa cơ bản. Điều này có nghĩa là không có trường hợp ngoại lệ nào có thể xảy ra và đặc biệt là SIGINT sẽ không kích hoạt KeyboardInterrupt.

Tăng ShutDown nếu hàng đợi đã bị tắt và trống hoặc nếu hàng đợi đã bị tắt ngay lập tức.

Queue.get_nowait()

Tương đương với get(False).

Hai phương pháp được cung cấp để hỗ trợ theo dõi xem các tác vụ trong hàng đợi đã được xử lý hoàn toàn bởi các luồng tiêu dùng daemon hay chưa.

Queue.task_done()

Cho biết rằng một nhiệm vụ được xếp hàng trước đó đã hoàn thành. Được sử dụng bởi các chủ đề tiêu dùng hàng đợi. Đối với mỗi get() được sử dụng để tìm nạp một tác vụ, một lệnh gọi tiếp theo tới task_done() sẽ thông báo cho hàng đợi rằng quá trình xử lý tác vụ đã hoàn tất.

Nếu một join() hiện đang bị chặn thì nó sẽ tiếp tục lại khi tất cả các mục đã được xử lý (có nghĩa là đã nhận được lệnh gọi task_done() cho mọi mục đã được put() đưa vào hàng đợi).

Tăng ValueError nếu được gọi nhiều lần hơn số mục được đặt trong hàng đợi.

Queue.join()

Chặn cho đến khi tất cả các mục trong hàng đợi đã được nhận và xử lý.

Số lượng nhiệm vụ chưa hoàn thành sẽ tăng lên bất cứ khi nào một mục được thêm vào hàng đợi. Số lượng giảm xuống bất cứ khi nào một luồng tiêu dùng gọi task_done() để cho biết rằng mục đó đã được truy xuất và tất cả công việc trên đó đã hoàn tất. Khi số lượng nhiệm vụ chưa hoàn thành giảm xuống 0, join() sẽ mở khóa.

Đang chờ hoàn thành nhiệm vụ

Ví dụ về cách chờ hoàn thành các tác vụ được xếp hàng đợi

nhập luồng
hàng đợi nhập khẩu

q = hàng đợi.Queue()

công nhân def():
    trong khi Đúng:
        mục = q.get()
        print(f'Đang làm việc trên {item}')
        print(f'Đã hoàn thành {item}')
        q.task_done()

# Turn-on luồng công nhân.
threading.Thread(target=worker, daemon=True).start()

# Send ba mươi yêu cầu nhiệm vụ cho nhân viên.
đối với mục trong phạm vi (30):
    q.put(mục)

# Block cho đến khi hoàn thành mọi nhiệm vụ.
q.join()
print('Tất cả công việc đã hoàn thành')

Chấm dứt hàng đợi

Khi không còn cần thiết, các đối tượng Queue có thể được thu gọn lại cho đến khi trống hoặc chấm dứt ngay lập tức bằng cách tắt máy cứng.

Queue.shutdown(immediate=False)

Đặt phiên bản Queue vào chế độ tắt máy.

Hàng đợi không thể phát triển được nữa. Các cuộc gọi trong tương lai tới put() sẽ tăng ShutDown. Những người gọi put() hiện bị chặn sẽ được bỏ chặn và sẽ gọi ShutDown trong chuỗi bị chặn trước đây.

Nếu immediate là sai (mặc định), hàng đợi có thể được kết thúc bình thường bằng các lệnh gọi get() để trích xuất các tác vụ đã được tải.

Và nếu task_done() được gọi cho mỗi nhiệm vụ còn lại, join() đang chờ xử lý sẽ được bỏ chặn bình thường.

Khi hàng đợi trống, các lệnh gọi tới get() trong tương lai sẽ tăng ShutDown.

Nếu immediate đúng, hàng đợi sẽ bị chấm dứt ngay lập tức. Hàng đợi được rút hết hoàn toàn trống và số lượng nhiệm vụ chưa hoàn thành sẽ giảm đi theo số lượng nhiệm vụ đã được rút hết. Nếu nhiệm vụ chưa hoàn thành bằng 0, người gọi join() sẽ được bỏ chặn. Ngoài ra, những người gọi bị chặn của get() sẽ được bỏ chặn và sẽ gọi ShutDown vì hàng đợi trống.

Hãy thận trọng khi sử dụng join() với immediate được đặt thành true. Điều này sẽ bỏ chặn sự tham gia ngay cả khi không có công việc nào được thực hiện đối với các tác vụ, vi phạm tính bất biến thông thường khi tham gia hàng đợi.

Added in version 3.13.

Đối tượng SimpleQueue

Các đối tượng SimpleQueue cung cấp các phương thức công khai được mô tả bên dưới.

SimpleQueue.qsize()

Trả về kích thước gần đúng của hàng đợi. Lưu ý, qsize() > 0 không đảm bảo rằng get() tiếp theo sẽ không bị chặn.

SimpleQueue.empty()

Trả về True nếu hàng đợi trống, False nếu không. Nếu trống() trả về False, điều đó không đảm bảo rằng lệnh gọi tiếp theo tới get() sẽ không bị chặn.

SimpleQueue.put(item, block=True, timeout=None)

Đặt item vào hàng đợi. Phương thức này không bao giờ chặn và luôn thành công (ngoại trừ các lỗi tiềm ẩn ở mức độ thấp như không phân bổ được bộ nhớ). Các đối số tùy chọn blocktimeout bị bỏ qua và chỉ được cung cấp để tương thích với Queue.put().

Phương pháp này có triển khai C được đăng ký lại. Nghĩa là, cuộc gọi put() hoặc get() có thể bị gián đoạn bởi một cuộc gọi put() khác trong cùng một chuỗi mà không gây bế tắc hoặc làm hỏng trạng thái bên trong hàng đợi. Điều này làm cho nó thích hợp để sử dụng trong các hàm hủy như phương thức __del__ hoặc lệnh gọi lại weakref.

SimpleQueue.put_nowait(item)

Tương đương với put(item, block=False), được cung cấp để tương thích với Queue.put_nowait().

SimpleQueue.get(block=True, timeout=None)

Xóa và trả lại một mục từ hàng đợi. Nếu các đối số tùy chọn block là đúng và timeoutNone (mặc định), hãy chặn nếu cần thiết cho đến khi có một mục. Nếu timeout là số dương, nó sẽ chặn tối đa timeout giây và tăng ngoại lệ Empty nếu không có mục nào có sẵn trong thời gian đó. Nếu không (block là sai), hãy trả lại một mục nếu có sẵn ngay lập tức, nếu không thì đưa ra ngoại lệ Empty (timeout bị bỏ qua trong trường hợp đó).

SimpleQueue.get_nowait()

Tương đương với get(False).

Xem thêm

Lớp multiprocessing.Queue

Một lớp hàng đợi để sử dụng trong ngữ cảnh đa xử lý (chứ không phải đa luồng).

collections.deque là một triển khai thay thế của hàng đợi không giới hạn với các hoạt động append()popleft() nguyên tử nhanh không yêu cầu khóa và cũng hỗ trợ lập chỉ mục.