Python Advance 📂 Queue · 1 of 1 323 min read

Queue Types in Python

Master every queue type with visual diagrams. Learn the 5 fundamental patterns — FIFO, LIFO, Priority, Deque, Circular — and every Python implementation: collections.deque, heapq, queue.Queue/LifoQueue/PriorityQueue/SimpleQueue, multiprocessing.Queue and JoinableQueue, asyncio.Queue. Includes a decision flowchart, backpressure diagram, comparison table, and real-world examples for each type.

🌐
SectionSection第 01 节

The Story That Explains All Queues 🚶सारी Queues समझाने वाली कहानी 🚶一个讲清所有队列的故事 🚶

Five Kinds of Line You Have Stood Inपाँच तरह की कतारें जिनमें आप खड़े हुए हैं你排过的五种队
Every day you meet queues. The coffee shop line: the first person in is served first (FIFO). The stack of trays in a canteen: the top one is taken first (LIFO). The hospital emergency room: a heart attack goes ahead of a broken finger (priority). The returns cart in a bookshop: staff add or take books from either end (deque). The airport luggage belt: a fixed loop of places that goes round and round (circular queue).

Each one is a different queue type — and each has a Python version. Picking the right one is the difference between a neat, fast program and a slow, buggy one.
हर दिन आप queues से मिलते हैं। कॉफ़ी की दुकान की कतार: पहले आया, पहले पाया (FIFO)। Canteen में ट्रे का ढेर: सबसे ऊपर वाली पहले उठती है (LIFO)। अस्पताल का emergency room: heart attack वाला टूटी उँगली वाले से पहले जाता है (priority)। किताबों की दुकान की returns cart: staff दोनों सिरों से किताबें रखता या निकालता है (deque)। हवाई अड्डे का luggage belt: तय जगहों का एक गोल चक्कर (circular queue)।

हर एक अलग queue type है — और हर एक का Python version है। सही चुनना ही साफ़-सुथरे, तेज़ program और धीमे, bugs भरे program का फ़र्क़ है।
你每天都在和队列打交道。咖啡店的队伍:先来的先被服务(FIFO)。食堂里的 一摞托盘:最上面的先被拿走(LIFO)。医院急诊室:心脏病发作的人排在手指骨折的人前面(优先级)。书店的 退货推车:店员可以从两端放书或取书(deque)。机场行李转盘:一圈固定的位置不停地转(循环队列)。

每一种都是不同的队列类型 — 每一种在 Python 里都有对应的实现。选对了,程序就简洁高效;选错了,程序就又慢又容易出 bug。
🧠
The Core Insightमूल बात核心要点

A queue is not one thing — it is a family. They all share the same idea (put items in, take items out) but differ in which item comes out next. This tutorial covers the 5 basic queue types and the Python tools you will really use for them.

Queue एक चीज़ नहीं — यह एक परिवार है। सबका विचार एक है (items डालो, items निकालो) पर फ़र्क़ इसमें है कि अगला कौन-सा item निकलेगा। यह tutorial 5 बुनियादी queue types और उनके लिए असल में इस्तेमाल होने वाले Python tools बताता है।

队列不是一种东西,而是一个家族。它们的思路相同(放进元素、取出元素),区别在于 下一个取出的是哪一个。本教程介绍 5 种基本队列类型,以及你在实际中会用到的 Python 工具。

▶️
Seven Simulators and a Quizसात Simulators और एक Quiz七个模拟器和一个小测验

Look for the interactive boxes: the Queue Playground (Section 02), the pop(0) Race (03), the Ring Buffer (07), the Heap Lab (11), the Backpressure Lab (12), the Queue Picker (16) and the Bug Doctor (17). Their results were checked against real Python.

Interactive डिब्बे खोजें: Queue Playground (Section 02), pop(0) Race (03), Ring Buffer (07), Heap Lab (11), Backpressure Lab (12), Queue Picker (16) और Bug Doctor (17)। इनके नतीजे असली Python से जाँचे गए हैं।

请留意这些互动框:队列游乐场(第 02 节)、pop(0) 赛跑(03)、环形缓冲区(07)、堆实验室(11)、背压实验室(12)、队列选择器(16)和 Bug 医生(17)。它们的结果都已与真实的 Python 核对。


SectionSection第 02 节

The Big Picture — All Queue Types at a Glance 🗺️बड़ी तस्वीर — सारे Queue Types एक नज़र में 🗺️全局视角 — 一眼看懂所有队列类型 🗺️

Five Queue Types Comparedपाँच Queue Types की तुलना五种队列类型对比
Five queue types comparedFIFOfirst in, first outपहले आया, पहले गया先进先出LIFOlast in, first outआख़िर में आया, पहले गया后进先出PRIORITYsmallest number firstसबसे छोटी संख्या पहले数字最小的先出DEQUEboth endsदोनों सिरे两端都可以CIRCULARfixed ring of slotsतय slots का घेरा固定的环形槽位ABCDout: A firstinABCDin & out: D firstB·1D·2A·3C·5out: lowest numberABCDin/out both endswraps around, never grows

Five basic patterns. Every Python queue is one of these ideas plus extra machinery (thread safety, blocking, size limits).

पाँच बुनियादी patterns। हर Python queue इन्हीं में से एक विचार है, साथ में अतिरिक्त machinery (thread safety, blocking, size limits)।

五种基本模式。每个 Python 队列都是其中一种思路,再加上额外的机制(线程安全、阻塞、容量限制)。

🎮 Simulator: Queue Playground🎮 Simulator: Queue Playground🎮 模拟器:队列游乐场

Pick a queue type, add and remove items, and watch which item comes out. The code on the left grows with every click. The results were checked against Python on 400 random sequences — including the exact error messages.

एक queue type चुनिए, items जोड़िए और निकालिए, और देखिए कौन-सा item बाहर आता है। हर click के साथ बाईं ओर का code बढ़ता है। नतीजे 400 random sequences पर Python से जाँचे गए — सटीक error messages समेत।

选一种队列类型,添加和移除元素,看看哪个元素先出来。左边的代码会随着每次点击增长。结果已在 400 个随机序列上与 Python 核对 — 包括精确的错误信息。

Queue PlaygroundQueue Playground队列游乐场400 sequences checked400 sequences जाँचे已核对 400 个序列
Type:Type:类型:
Priority of next item:अगले item की priority:下一个元素的优先级:
Do:करें:操作:
CodeCode代码
OutputOutput输出

SectionSection第 03 节

Type 1 — FIFO Queue (First In, First Out) ☕Type 1 — FIFO Queue (पहले आया, पहले गया) ☕类型 1 — FIFO 队列(先进先出)☕

The default and most natural queue. Items join at the tail and leave from the head, in exactly the order they arrived — the coffee shop line.

सबसे आम और स्वाभाविक queue। Items tail पर जुड़ते हैं और head से निकलते हैं, ठीक उसी क्रम में जिसमें आए — कॉफ़ी की दुकान की कतार।

最常见、最自然的队列。元素从 队尾 进入,从 队头 离开,严格按照到达的顺序 — 就像咖啡店的队伍。

FIFO — Same Order In and OutFIFO — अंदर-बाहर एक ही क्रमFIFO — 进出顺序一致
FIFO flowHEAD (leaves here)HEAD (यहाँ से निकलता)队头(从这里离开)TAIL (joins here)TAIL (यहाँ जुड़ता)队尾(从这里加入)12345append()popleft()items leave in the same order they arrived: 1, 2, 3, 4, 5items उसी क्रम में निकलते हैं जिसमें आए: 1, 2, 3, 4, 5元素按到达的顺序离开:1、2、3、4、5
from collections import deque

# deque = the fast Python FIFO (O(1) at both ends)
q = deque()
q.append("A")          # enqueue at the tail
q.append("B")
q.append("C")

print(q.popleft())     # "A" - dequeue from the head
print(q.popleft())     # "B"
print(q.popleft())     # "C"
OUTPUT
A B C
🔧
Fixed: How Much Slower Is list.pop(0)?सुधार: list.pop(0) कितना धीमा है?已修正:list.pop(0) 到底慢多少?

The original said that for 10,000 items list.pop(0) is "10,000× slower" than deque.popleft(). We measured it. Each pop(0) shifts every remaining item, so the gap grows with the size of the list — but at 10,000 items it is closer to 20×, not 10,000×. At 100,000 items it reaches a few hundred times. Real timings:

मूल में कहा गया कि 10,000 items पर list.pop(0), deque.popleft() से "10,000× धीमा" है। हमने नापा। हर pop(0) बाक़ी सारे items खिसकाता है, इसलिए फ़र्क़ list के size के साथ बढ़ता है — पर 10,000 items पर यह लगभग 20× है, 10,000× नहीं। 100,000 items पर यह कुछ सौ गुना तक पहुँचता है। असली timings:

原文说对于 10,000 个元素,list.pop(0) 比 deque.popleft()"慢 10,000 倍"。我们实测了。每次 pop(0) 都要移动剩下的所有元素,所以差距 随列表长度增长 — 但在 10,000 个元素时大约是 20 倍,而不是 10,000 倍。到 100,000 个元素时才达到几百倍。真实计时:

import timeit

for n in (1_000, 10_000, 100_000):
    t_list = timeit.timeit("while q: q.pop(0)",
                           setup=f"q = list(range({n}))", number=1)
    t_deque = timeit.timeit("while q: q.popleft()",
                            setup=f"from collections import deque; q = deque(range({n}))", number=1)
    print(f"{n:>7,} items: list.pop(0) {t_list*1000:8.2f} ms | "
          f"deque.popleft() {t_deque*1000:6.2f} ms | {t_list/t_deque:5.0f}x slower")
OUTPUT
1,000 items: list.pop(0) 0.11 ms | deque.popleft() 0.02 ms | 4x slower 10,000 items: list.pop(0) 5.26 ms | deque.popleft() 0.28 ms | 19x slower 100,000 items: list.pop(0) 776.18 ms | deque.popleft() 3.06 ms | 254x slower

🏁 Simulator: pop(0) Race🏁 Simulator: pop(0) Race🏁 模拟器:pop(0) 赛跑

Watch why pop(0) is slow: after removing the first item, every other item must move one place left. popleft() just moves the start. The bars show real timings for emptying a whole queue (best of 3 runs on our test machine).

देखिए pop(0) धीमा क्यों है: पहला item हटाने के बाद हर दूसरे item को एक जगह बाईं ओर खिसकना पड़ता है। popleft() बस शुरुआत आगे बढ़ाता है। Bars पूरी queue ख़ाली करने की असली timings दिखाते हैं (हमारी test machine पर 3 runs में सबसे अच्छा)।

看看 pop(0) 为什么慢:移除第一个元素后,其余每个元素都要向左挪一位。popleft() 只是移动起点。条形图显示清空整个队列的真实耗时(在我们测试机上 3 次运行中的最好成绩)。

pop(0) Racepop(0) Racepop(0) 赛跑real timingsअसली timings真实计时
Remove the first item with:पहला item हटाएँ:用以下方式移除第一个元素:
Time to empty a queue of N itemsN items की queue ख़ाली करने का समय清空 N 个元素的队列所需时间
■ list.pop(0) ■ deque.popleft()
🐢
Do Not Use a List as a FIFOList को FIFO की तरह मत लीजिए不要把列表当 FIFO 用

A list lets you write lst.pop(0), but it is O(n): every remaining item shifts down. For small lists you will not notice; for large, busy queues it becomes the slowest part of your program. Use deque or queue.Queue for FIFO.

List में lst.pop(0) लिख सकते हैं, पर यह O(n) है: बाक़ी हर item नीचे खिसकता है। छोटी lists में पता नहीं चलेगा; बड़ी, व्यस्त queues में यह आपके program का सबसे धीमा हिस्सा बन जाता है। FIFO के लिए deque या queue.Queue लीजिए।

列表可以写 lst.pop(0),但它是 O(n) 的:剩下的每个元素都要往前挪。列表小时你察觉不到;队列又大又忙时,它会成为程序里最慢的部分。FIFO 请用 deque 或 queue.Queue。


SectionSection第 04 节

Type 2 — LIFO Queue (Stack) 🍽️Type 2 — LIFO Queue (Stack) 🍽️类型 2 — LIFO 队列(栈)🍽️

A stack. Items go in and come out at the same end — the top. The last thing you added is the first thing you get back. Perfect for undo history, function calls and depth-first search.

एक stack। Items एक ही सिरे — top — से अंदर जाते और बाहर आते हैं। जो आख़िर में डाला, वही सबसे पहले वापस मिलता है। Undo history, function calls और depth-first search के लिए बढ़िया।

这就是 栈。元素从同一端 — 顶部 — 进出。最后放进去的最先拿回来。非常适合撤销历史、函数调用和深度优先搜索。

LIFO — Push and Pop at the TopLIFO — Top पर Push और PopLIFO — 在顶部压入和弹出
LIFO stack push and popABCDappend("D")push → toppop() → "D"top comes out firstTOPTOP顶部BOTTOMBOTTOM底部like a stack of platesप्लेटों के ढेर जैसा就像一摞盘子
# Option A: Python list as a stack (O(1) at the end)
stack = []
stack.append("A")          # push
stack.append("B")
stack.append("C")
print(stack.pop())         # "C" - last in, first out
print(stack.pop())         # "B"

# Option B: collections.deque (also O(1); append/pop are thread-safe)
from collections import deque
stack = deque()
stack.append("A")
stack.append("B")
print(stack.pop())         # "B"

# Option C: queue.LifoQueue (thread-safe, blocking API)
from queue import LifoQueue
s = LifoQueue()
s.put("A"); s.put("B"); s.put("C")
print(s.get())             # "C"
OUTPUT
C B B C
💡
Real Uses of LIFOLIFO के असली उपयोगLIFO 的实际用途

Undo/redo history (the last action is undone first), the function-call stack (the last function called returns first), backtracking, depth-first search, matching brackets in a parser, and the browser back button.

Undo/redo history (आख़िरी action सबसे पहले undo), function-call stack (आख़िर में बुलाया function पहले लौटता है), backtracking, depth-first search, parser में brackets मिलाना, और browser का back button।

撤销/重做历史(最后的操作最先撤销)、函数调用栈(最后调用的函数最先返回)、回溯算法、深度优先搜索、解析器中的括号匹配,以及浏览器的后退按钮。


SectionSection第 05 节

Type 3 — Priority Queue 🏥Type 3 — Priority Queue 🏥类型 3 — 优先队列 🏥

Items do not come out in the order they went in. Each item has a priority, and the most urgent one always comes out first. In Python "most urgent" means the smallest number, because Python's priority queues are min-heaps.

Items उस क्रम में बाहर नहीं आते जिसमें अंदर गए। हर item की एक priority होती है, और सबसे ज़रूरी हमेशा पहले निकलता है। Python में "सबसे ज़रूरी" का मतलब सबसे छोटी संख्या है, क्योंकि Python की priority queues min-heaps हैं।

元素 不会 按进入的顺序出来。每个元素都有一个优先级,最紧急的总是最先出来。在 Python 中,"最紧急"指的是 最小 的数字,因为 Python 的优先队列都是最小堆。

Priority Queue — Most Urgent FirstPriority Queue — सबसे ज़रूरी पहले优先队列 — 最紧急的先出
Priority queue triageARRIVAL ORDERआने का क्रम到达顺序TREATMENT ORDERइलाज का क्रम就诊顺序5Change ink1Heart attack3Cough1Stroke2Broken arm1Heart attack1Stroke2Broken arm3Cough5Change inkheappop()smallest number firstसबसे छोटी संख्या पहले数字最小的先出
# Option A: heapq - the low-level, fast min-heap
import heapq
pq = []
heapq.heappush(pq, (5, "Change ink"))
heapq.heappush(pq, (1, "Heart attack"))
heapq.heappush(pq, (3, "Cough"))
heapq.heappush(pq, (1, "Stroke"))
heapq.heappush(pq, (2, "Broken arm"))

while pq:
    print(heapq.heappop(pq))

# Option B: queue.PriorityQueue - thread-safe, blocking API
from queue import PriorityQueue
pq = PriorityQueue()
pq.put((5, "low urgency"))
pq.put((1, "urgent!"))
print(pq.get())            # (1, 'urgent!')
OUTPUT
(1, 'Heart attack') (1, 'Stroke') (2, 'Broken arm') (3, 'Cough') (5, 'Change ink') (1, 'urgent!')
⚖️
What Happens on a Tie?बराबरी पर क्या होता है?优先级相同时会怎样?

Heart attack and Stroke both have priority 1. Tuples are compared item by item, so Python then compares the names: "Heart attack" < "Stroke", so Heart attack comes first. That works for strings — but if the second item cannot be compared (a dict, a custom object), you get a TypeError. Section 11 shows this and the fix.

Heart attack और Stroke दोनों की priority 1 है। Tuples की तुलना item दर item होती है, इसलिए Python फिर नामों की तुलना करता है: "Heart attack" < "Stroke", इसलिए Heart attack पहले आता है। Strings के लिए यह चलता है — पर अगर दूसरे item की तुलना न हो सके (dict, custom object), तो TypeError आता है। Section 11 इसे और इसका इलाज दिखाता है।

心脏病发作和中风的优先级都是 1。元组是逐项比较的,所以 Python 接着比较 名称:"Heart attack" < "Stroke",于是心脏病发作排在前面。对字符串这样没问题 — 但如果第二项无法比较(字典、自定义对象),就会得到 TypeError。第 11 节会演示这个问题及修正方法。


SectionSection第 06 节

Type 4 — Deque (Double-Ended Queue) ↔️Type 4 — Deque (दोनों सिरों वाली Queue) ↔️类型 4 — 双端队列 Deque ↔️

Pronounced "deck". You can add or remove at either end in O(1). A deque can act as a FIFO, a LIFO, or both at once. collections.deque is the most flexible queue in the standard library.

"डेक" बोला जाता है। आप किसी भी सिरे पर O(1) में जोड़ या निकाल सकते हैं। Deque FIFO, LIFO, या दोनों एक साथ बन सकता है। collections.deque standard library की सबसे लचीली queue है।

读作 "deck"。你可以在 任意一端 以 O(1) 的速度添加或移除元素。deque 既能当 FIFO,也能当 LIFO,或者同时兼任。collections.deque 是标准库里最灵活的队列。

Deque — Four Operations, Both EndsDeque — चार Operations, दोनों सिरेDeque — 四种操作,两端皆可
Deque operationsBCDAEappendleft("A")popleft()append("E")pop()all four operations are O(1)चारों operations O(1) हैं四种操作都是 O(1)
from collections import deque

d = deque(["B", "C", "D"])

# Add to either end
d.appendleft("A")
d.append("E")
print(d)                   # deque(['A', 'B', 'C', 'D', 'E'])

# Remove from either end
print(d.popleft())         # "A"
print(d.pop())             # "E"
print(d)                   # deque(['B', 'C', 'D'])

# Bounded deque - drops from the OPPOSITE end when full
recent = deque(maxlen=3)
for i in range(6):
    recent.append(i)
print(recent)              # deque([3, 4, 5], maxlen=3)

# Rotate - a fast circular shift
d = deque([1, 2, 3, 4, 5])
d.rotate(2)
print(d)                   # deque([4, 5, 1, 2, 3])
d.rotate(-1)
print(d)                   # deque([5, 1, 2, 3, 4])
OUTPUT
deque(['A', 'B', 'C', 'D', 'E']) A E deque(['B', 'C', 'D']) deque([3, 4, 5], maxlen=3) deque([4, 5, 1, 2, 3]) deque([5, 1, 2, 3, 4])
🏆
Killer Feature — maxlenसबसे बढ़िया Feature — maxlen杀手级特性 — maxlen

deque(maxlen=100) gives you a bounded queue for free — perfect for "last N items" buffers (recent log lines, a moving-average window, recent history). When it is full, adding on one end silently drops an item from the other end.

deque(maxlen=100) आपको मुफ़्त में सीमित queue देता है — "आख़िरी N items" buffers के लिए बढ़िया (हाल की log lines, moving-average window, हाल का इतिहास)। भरने पर एक सिरे पर जोड़ने से दूसरे सिरे का item चुपचाप हट जाता है।

deque(maxlen=100) 免费给你一个有界队列 — 非常适合"最近 N 个元素"的缓冲区(最近的日志行、移动平均窗口、最近的历史记录)。满了之后,在一端添加会悄悄从 另一端 丢掉一个元素。

🔧
Fixed: Comments That Looked Like Outputसुधार: Output जैसे दिखने वाले Comments已修正:看起来像输出的注释

In the original deque example, lines like d.appendleft("A") # [A, B, C, D] and d.rotate(2) # deque([4, 5, 1, 2, 3]) only had the result in a comment — nothing was printed. We added print() calls so the output above really shows each state.

मूल deque example में d.appendleft("A") # [A, B, C, D] और d.rotate(2) # deque([4, 5, 1, 2, 3]) जैसी lines में नतीजा सिर्फ़ comment में था — कुछ print नहीं होता था। हमने print() जोड़े ताकि ऊपर का output सच में हर स्थिति दिखाए।

原 deque 示例中,像 d.appendleft("A") # [A, B, C, D] 和 d.rotate(2) # deque([4, 5, 1, 2, 3]) 这样的行只是把结果写在注释里 — 实际上什么都没打印。我们加上了 print(),让上面的输出真实显示每一步的状态。


SectionSection第 07 节

Type 5 — Circular Queue (Ring Buffer) 🔁Type 5 — Circular Queue (Ring Buffer) 🔁类型 5 — 循环队列(环形缓冲区)🔁

A fixed-size queue where the head and tail positions wrap around from the end of the storage back to the start. It never grows and never shrinks — perfect when memory must stay fixed: audio buffers, sensor readings, network packets.

एक तय size की queue जिसमें head और tail की जगहें storage के अंत से वापस शुरुआत पर घूम जाती हैं। यह न बढ़ती है, न घटती है — जब memory तय रखनी हो तब बढ़िया: audio buffers, sensor readings, network packets।

一个固定大小的队列,head 和 tail 的位置会从存储末尾 绕回 开头。它从不增长也从不缩小 — 非常适合内存必须固定的场景:音频缓冲、传感器读数、网络数据包。

Building a circular queue from scratchCircular queue शुरू से बनाना从零实现循环队列

class CircularQueue:
    def __init__(self, capacity):
        self.buf = [None] * capacity
        self.cap = capacity
        self.head = 0          # index to read from
        self.tail = 0          # index to write to
        self.size = 0

    def enqueue(self, item):
        if self.size == self.cap:
            raise OverflowError("Queue full")
        self.buf[self.tail] = item
        self.tail = (self.tail + 1) % self.cap     # wrap around!
        self.size += 1

    def dequeue(self):
        if self.size == 0:
            raise IndexError("Queue empty")
        item = self.buf[self.head]
        self.buf[self.head] = None
        self.head = (self.head + 1) % self.cap     # wrap around!
        self.size -= 1
        return item

    def __len__(self):
        return self.size

# Demo
cq = CircularQueue(4)
for ch in "ABCD":
    cq.enqueue(ch)
print(cq.dequeue(), cq.dequeue())    # A B
cq.enqueue("E"); cq.enqueue("F")     # tail wraps back to slot 0
print(cq.buf)                        # ['E', 'F', 'C', 'D']
OUTPUT
A B ['E', 'F', 'C', 'D']

🔁 Simulator: Ring Buffer🔁 Simulator: Ring Buffer🔁 模拟器:环形缓冲区

Enqueue and dequeue on a ring of 6 slots. Watch head and tail go round and wrap back to slot 0. Then switch to deque(maxlen=6): instead of an error when full, it quietly drops the oldest item. Both were checked against Python on 300 random sequences.

6 slots वाले घेरे पर enqueue और dequeue कीजिए। head और tail को घूमते और slot 0 पर लौटते देखिए। फिर deque(maxlen=6) पर जाइए: भरने पर error की जगह यह चुपचाप सबसे पुराना item हटा देता है। दोनों 300 random sequences पर Python से जाँचे गए।

在一个有 6 个槽位的环上入队和出队。观察 head 和 tail 如何转圈并绕回槽位 0。然后切换到 deque(maxlen=6):满了时它不会报错,而是悄悄丢掉最旧的元素。两者都已在 300 个随机序列上与 Python 核对。

Ring BufferRing Buffer环形缓冲区300 sequences checked300 sequences जाँचे已核对 300 个序列
Version:Version:版本:
OutputOutput输出

Shortcut — deque(maxlen=…) as a circular bufferछोटा रास्ता — deque(maxlen=…) circular buffer की तरह捷径 — 用 deque(maxlen=…) 作环形缓冲区

from collections import deque

# A ring of the last 5 sensor readings
ring = deque(maxlen=5)
for reading in [10, 11, 13, 12, 14, 15, 16]:
    ring.append(reading)     # old readings drop off the LEFT automatically

print(ring)                  # deque([13, 12, 14, 15, 16], maxlen=5)
print(sum(ring) / len(ring)) # rolling average
OUTPUT
deque([13, 12, 14, 15, 16], maxlen=5) 14.0
🔍
Two Kinds of "Full""भरा हुआ" के दो प्रकार两种"满"

The two versions behave differently when full. The hand-written CircularQueue refuses new items (OverflowError) — no data is lost. deque(maxlen=N) overwrites the oldest item — always room for the newest. Choose the one that matches what losing data means for you.

भरने पर दोनों versions अलग व्यवहार करते हैं। हाथ से लिखी CircularQueue नए items लेने से मना करती है (OverflowError) — कोई data नहीं खोता। deque(maxlen=N) सबसे पुराने item को ऊपर से लिख देता है — सबसे नए के लिए हमेशा जगह। वह चुनिए जो आपके लिए data खोने के मतलब से मेल खाए।

两个版本在满了的时候表现不同。手写的 CircularQueue 会 拒绝 新元素(OverflowError)— 不丢数据。deque(maxlen=N) 会 覆盖 最旧的元素 — 永远给最新的留位置。根据丢数据对你意味着什么来选择。


SectionSection第 08 节

Python's queue Module — Thread-Safe Queues 🔒Python का queue Module — Thread-Safe Queues 🔒Python 的 queue 模块 — 线程安全队列 🔒

The types above are ideas. When several threads share a queue, use the queue module: its classes lock for you, and their put()/get() can wait (block) until there is space or an item.

ऊपर के types विचार हैं। जब कई threads एक queue बाँटें, तो queue module लीजिए: इसकी classes आपके लिए lock करती हैं, और इनके put()/get() जगह या item मिलने तक इंतज़ार (block) कर सकते हैं।

上面的类型只是概念。当多个 线程 共享一个队列时,请使用 queue 模块:它的类会替你加锁,put()/get() 还能 等待(阻塞)直到有空位或有元素。

ClassClass类Orderक्रम顺序Size limit?Size limit?容量限制?task_done / join?task_done / join?task_done / join?When to useकब लें何时使用
QueueFIFOYes (maxsize)हाँ (maxsize)有(maxsize)Yesहाँ有The default work queue for threadsThreads के लिए default work queue线程间默认的工作队列
LifoQueueLIFOYesहाँ有Yesहाँ有A stack shared by threadsThreads में बँटा stack线程共享的栈
PriorityQueuePriority (min-heap)Priority (min-heap)优先级(最小堆)Yesहाँ有Yesहाँ有Task scheduling by urgencyज़रूरत के हिसाब से task scheduling按紧急程度调度任务
SimpleQueueFIFONo (unbounded)नहीं (असीमित)无(无界)Noनहीं无Simple, fast hand-offsसरल, तेज़ hand-offs简单、快速的交接
from queue import Queue, LifoQueue, PriorityQueue, SimpleQueue

# 1. Standard FIFO Queue
q = Queue(maxsize=10)
q.put("A"); q.put("B"); q.put("C")
print(q.get())             # A

# 2. Stack (LIFO)
s = LifoQueue()
s.put("A"); s.put("B"); s.put("C")
print(s.get())             # C - last in, first out

# 3. Priority (lowest number wins)
p = PriorityQueue()
p.put((3, "low"))
p.put((1, "urgent"))
p.put((2, "med"))
print(p.get())             # (1, 'urgent')

# 4. SimpleQueue - no maxsize, no join(), fastest
sq = SimpleQueue()
sq.put("fast")
print(sq.get())            # fast
OUTPUT
A C (1, 'urgent') fast

How much faster is SimpleQueue?SimpleQueue कितना तेज़ है?SimpleQueue 快多少?

import timeit

for name in ("Queue", "SimpleQueue"):
    t = timeit.timeit("for i in r: q.put(i)\nfor i in r: q.get()",
                      setup=f"import queue; r = range(100_000); q = queue.{name}()",
                      number=1)
    print(f"{name:12s} 100,000 put+get: {t*1000:6.1f} ms")
OUTPUT
Queue 100,000 put+get: 106.2 ms SimpleQueue 100,000 put+get: 7.1 ms
⚡
Why SimpleQueue Is FasterSimpleQueue तेज़ क्यों हैSimpleQueue 为什么更快

SimpleQueue is written in C and skips maxsize, task_done() and join(). In our run it was more than 10× faster for plain put/get. Use Queue when you need a size limit or join(); otherwise SimpleQueue is enough.

SimpleQueue C में लिखा है और maxsize, task_done() और join() छोड़ देता है। हमारे run में सादे put/get पर यह 10× से ज़्यादा तेज़ था। Size limit या join() चाहिए तो Queue लीजिए; वरना SimpleQueue काफ़ी है।

SimpleQueue 用 C 实现,省掉了 maxsize、task_done() 和 join()。在我们的运行中,单纯的 put/get 快了 10 倍以上。需要容量限制或 join() 时用 Queue;否则 SimpleQueue 就够了。


SectionSection第 09 节

Multiprocessing Queues — Between Processes 📫Multiprocessing Queues — Processes के बीच 📫多进程队列 — 进程之间 📫

The queue module works only between threads (one shared memory). Separate processes have separate memory, so use multiprocessing.Queue or JoinableQueue: they pickle each object and send it through a pipe.

queue module सिर्फ़ threads के बीच चलता है (एक साझा memory)। अलग processes की memory अलग होती है, इसलिए multiprocessing.Queue या JoinableQueue लीजिए: ये हर object को pickle करके pipe से भेजते हैं।

queue 模块只能在 线程 之间使用(共享同一块内存)。不同的 进程 内存是分开的,所以要用 multiprocessing.Queue 或 JoinableQueue:它们会把每个对象 pickle 后通过管道发送。

Threads vs ProcessesThreads बनाम Processes线程 vs 进程
Threading queue vs multiprocessing queueTHREADS — one processTHREADS — एक process线程 — 同一进程shared memoryसाझा memory共享内存thread 1thread 2queue.Queuepasses references — no copyingreferences भेजता है — कोई copy नहीं传递引用 — 不复制PROCESSES — separate memoryPROCESSES — अलग memory进程 — 独立内存process 1own memoryअपनी memory自己的内存process 2own memoryअपनी memory自己的内存pickle → pipe → unpickleevery item is copied (slower)हर item copy होता है (धीमा)每个元素都被复制(更慢)

Threads share memory, so a thread queue passes references. Processes do not, so every item is pickled, sent and rebuilt.

Threads memory बाँटते हैं, इसलिए thread queue references भेजती है। Processes नहीं बाँटते, इसलिए हर item pickle, send और फिर से बनाया जाता है।

线程共享内存,所以线程队列传递的是引用。进程不共享,所以每个元素都要被 pickle、发送再重建。

from multiprocessing import Process, JoinableQueue

def worker(q):
    while True:
        item = q.get()
        if item is None:
            break
        print(f"got {item}", flush=True)
        q.task_done()              # only on JoinableQueue

if __name__ == "__main__":
    q = JoinableQueue()            # like Queue + task_done/join
    p = Process(target=worker, args=(q,))
    p.start()
    for i in range(5):
        q.put(f"task {i}")
    q.join()                       # wait for all task_done()
    q.put(None)                    # poison pill
    p.join()
    print("all done")
OUTPUT
got task 0 got task 1 got task 2 got task 3 got task 4 all done
🪟
Keep the __main__ Guard__main__ Guard रखिए保留 __main__ 保护

On Windows and macOS, new processes start by importing your script again. Without if __name__ == "__main__": the child would start more children. Also note flush=True in the worker's print: output from a child process may otherwise arrive late or out of order.

Windows और macOS पर नए processes आपकी script को फिर से import करके शुरू होते हैं। if __name__ == "__main__": के बिना child और children शुरू कर देगा। Worker के print में flush=True भी देखिए: वरना child process का output देर से या ग़लत क्रम में आ सकता है।

在 Windows 和 macOS 上,新进程启动时会重新导入你的脚本。没有 if __name__ == "__main__": 的话,子进程会再启动更多子进程。另外注意 worker 的 print 里有 flush=True:否则子进程的输出可能延迟或乱序。


SectionSection第 10 节

asyncio.Queue — For async/await Code ⚡asyncio.Queue — async/await Code के लिए ⚡asyncio.Queue — 用于 async/await 代码 ⚡

Inside asyncio code, use asyncio.Queue. It looks like queue.Queue, but put() and get() are coroutines you must await. It is not thread-safe — it is safe between tasks inside one event loop.

asyncio code में asyncio.Queue लीजिए। यह queue.Queue जैसा दिखता है, पर put() और get() coroutines हैं जिन्हें await करना होता है। यह thread-safe नहीं है — यह एक event loop के अंदर tasks के बीच सुरक्षित है।

在 asyncio 代码中,请使用 asyncio.Queue。它看起来像 queue.Queue,但 put() 和 get() 是必须 await 的协程。它 不是线程安全的 — 它只在同一个事件循环内的任务之间是安全的。

import asyncio

async def producer(q, name):
    for i in range(3):
        await asyncio.sleep(0.1)
        await q.put(f"{name}-{i}")

async def consumer(q, name):
    while True:
        item = await q.get()
        if item is None:
            break
        print(f"[{name}] got {item}")
        q.task_done()

async def main():
    q = asyncio.Queue(maxsize=10)
    prods = [asyncio.create_task(producer(q, f"P{i}")) for i in range(2)]
    cons = [asyncio.create_task(consumer(q, f"C{i}")) for i in range(3)]
    await asyncio.gather(*prods)
    await q.join()
    for _ in cons:
        await q.put(None)
    await asyncio.gather(*cons)

asyncio.run(main())
OUTPUT
[C0] got P0-0 [C0] got P1-0 [C2] got P0-1 [C2] got P1-1 [C1] got P0-2 [C1] got P1-2
📝
Small Change for a Readable Runपढ़ने लायक Run के लिए छोटा बदलाव为了便于阅读的小改动

We made each producer send 3 items instead of 5 so the real output stays short. Notice that items are shared across the three consumers — whichever consumer is free takes the next item.

हमने हर producer से 5 की जगह 3 items भिजवाए ताकि असली output छोटा रहे। ध्यान दीजिए, items तीनों consumers में बँटते हैं — जो consumer ख़ाली हो, अगला item वही लेता है।

我们让每个生产者只发送 3 个元素而不是 5 个,好让真实输出保持简短。注意元素会在三个消费者之间分配 — 哪个消费者空闲,就由它取下一个元素。

⚠️
Never Mix Queue Types Across Contextsअलग-अलग Contexts में Queue Types मत मिलाइए不要跨场景混用队列类型

A blocking queue.Queue.get() inside async code freezes the whole event loop (see the Bug Doctor). asyncio.Queue used from other threads is not synchronised. multiprocessing.Queue between threads works but is overkill. One rule: pick the queue that matches your concurrency model.

Async code में blocking queue.Queue.get() पूरा event loop जमा देता है (Bug Doctor देखिए)। दूसरे threads से इस्तेमाल किया asyncio.Queue synchronised नहीं होता। Threads के बीच multiprocessing.Queue चलता है पर ज़रूरत से ज़्यादा है। एक नियम: अपने concurrency model से मेल खाती queue चुनिए।

在异步代码中调用会阻塞的 queue.Queue.get() 会冻结整个事件循环(见 Bug 医生)。从其他线程使用 asyncio.Queue 不会正确同步。在线程之间用 multiprocessing.Queue 可以,但杀鸡用牛刀。一条规则:选择与你的并发模型相匹配的队列。


SectionSection第 11 节

heapq — The Raw Priority-Queue Building Block 🌲heapq — Priority Queue की बुनियादी ईंट 🌲heapq — 优先队列的基础构件 🌲

heapq turns a normal list into a min-heap. PriorityQueue uses it inside, plus locking. With no locking, it is the fastest choice for single-threaded priority work.

heapq एक सामान्य list को min-heap बना देता है। PriorityQueue अंदर से इसी को इस्तेमाल करता है, साथ में locking। बिना locking के यह single-thread priority काम के लिए सबसे तेज़ विकल्प है।

heapq 把普通列表变成 最小堆。PriorityQueue 内部就是用它再加上锁。没有锁的开销,它是单线程优先级任务的最快选择。

import heapq

# A heap is just a plain list, treated with heap operations
h = []
for x in [3, 1, 4, 1, 5]:
    heapq.heappush(h, x)
print(heapq.heappop(h))        # 1 (smallest first)
print(heapq.heappop(h))        # 1
print(heapq.heappop(h))        # 3

# Turn an existing list into a heap in O(n)
data = [7, 3, 9, 1, 4, 2]
heapq.heapify(data)            # in place
print(data)                    # [1, 3, 2, 7, 4, 9]

# Top-K largest / smallest in O(n log k)
print(heapq.nlargest(3, data))     # [9, 7, 4]
print(heapq.nsmallest(3, data))    # [1, 2, 3]
OUTPUT
1 1 3 [1, 3, 2, 7, 4, 9] [9, 7, 4] [1, 2, 3]
🌳
Why the Heap List Looks "Unsorted"Heap List "बेतरतीब" क्यों दिखती है为什么堆列表看起来"没排序"

After heapify, the list is [1, 3, 2, 7, 4, 9] — not sorted! A heap only promises that each parent is ≤ its children (item i ≤ items 2i+1 and 2i+2). So h[0] is always the smallest, and that is all you need for a priority queue. See it as a tree in the Heap Lab below.

heapify के बाद list [1, 3, 2, 7, 4, 9] है — sorted नहीं! Heap सिर्फ़ यह वादा करता है कि हर parent अपने children से ≤ है (item i ≤ items 2i+1 और 2i+2)। इसलिए h[0] हमेशा सबसे छोटा है, और priority queue के लिए बस इतना ही चाहिए। नीचे Heap Lab में इसे tree के रूप में देखिए।

heapify 之后列表是 [1, 3, 2, 7, 4, 9] — 并没有排序!堆只保证每个父节点 ≤ 它的子节点(第 i 项 ≤ 第 2i+1 和 2i+2 项)。所以 h[0] 永远是最小的,而这正是优先队列所需要的全部。在下面的堆实验室里以树的形式看看。

🌲 Simulator: Heap Lab🌲 Simulator: Heap Lab🌲 模拟器:堆实验室

Push numbers and pop the smallest. Watch a new item bubble up past bigger parents, and after a pop watch the last item move to the top and sink down. The list on the right is exactly what Python's heapq stores — checked on 300 random sequences.

Numbers push कीजिए और सबसे छोटा pop कीजिए। नए item को बड़े parents से ऊपर उठते देखिए, और pop के बाद आख़िरी item को top पर आकर नीचे बैठते देखिए। दाईं ओर की list ठीक वही है जो Python का heapq रखता है — 300 random sequences पर जाँची गई।

压入数字、弹出最小值。观察新元素如何越过更大的父节点 向上冒;弹出后,观察最后一个元素如何移到顶部再 向下沉。右边的列表正是 Python 的 heapq 存储的内容 — 已在 300 个随机序列上核对。

Heap LabHeap Lab堆实验室300 sequences checked300 sequences जाँचे已核对 300 个序列
heappush:
LogLog记录

Equal priorities — the TypeError trapबराबर priorities — TypeError का जाल优先级相同 — TypeError 陷阱

import heapq

pq = []
heapq.heappush(pq, (1, {"task": "first urgent"}))
try:
    heapq.heappush(pq, (1, {"task": "second urgent"}))   # same priority!
except TypeError as e:
    print("TypeError:", e)
OUTPUT
TypeError: '<' not supported between instances of 'dict' and 'dict'
import heapq, itertools

# Priority queue with a tie-breaker counter
counter = itertools.count()
pq = []
heapq.heappush(pq, (1, next(counter), {"task": "first urgent"}))
heapq.heappush(pq, (1, next(counter), {"task": "second urgent"}))
heapq.heappush(pq, (3, next(counter), {"task": "normal"}))

while pq:
    print(heapq.heappop(pq)[2]["task"])
OUTPUT
first urgent second urgent normal
🔧
Fixed: When Is a Tie-Breaker Needed?सुधार: Tie-Breaker कब ज़रूरी है?已修正:什么时候需要打破平局的计数器?

The original tie-breaker example used plain strings as the data. With strings a tie never fails — Python just compares the strings — so the example did not show why the counter matters. It matters when the data cannot be compared, like the dicts above. The counter also keeps equal priorities in arrival order (FIFO), which plain strings do not: they come out alphabetically.

मूल tie-breaker example में data के रूप में सादी strings थीं। Strings के साथ tie कभी fail नहीं होता — Python बस strings की तुलना करता है — इसलिए example यह नहीं दिखाता था कि counter क्यों ज़रूरी है। यह तब ज़रूरी है जब data की तुलना न हो सके, जैसे ऊपर के dicts। Counter बराबर priorities को आने के क्रम (FIFO) में भी रखता है, जो सादी strings नहीं करतीं: वे वर्णमाला के क्रम में निकलती हैं।

原来的平局示例用的是普通字符串作为数据。用字符串时平局永远不会出错 — Python 只是比较字符串 — 所以那个例子没能说明计数器为什么重要。当数据 无法比较 时(比如上面的字典),它才重要。计数器还能让相同优先级的元素保持到达顺序(FIFO),而普通字符串做不到:它们会按字母顺序出来。


SectionSection第 12 节

Bounded vs Unbounded Queues — Backpressure 🚰सीमित बनाम असीमित Queues — Backpressure 🚰有界 vs 无界队列 — 背压 🚰

If producers add items faster than consumers remove them, an unbounded queue just keeps growing — until memory runs out. A bounded queue (Queue(maxsize=N)) makes put() wait when it is full. The producers slow down to the consumers' speed. This is called backpressure.

अगर producers items को consumers के निकालने से तेज़ डालें, तो असीमित queue बढ़ती ही जाती है — memory ख़त्म होने तक। सीमित queue (Queue(maxsize=N)) भरने पर put() को इंतज़ार कराती है। Producers consumers की गति पर धीमे हो जाते हैं। इसे backpressure कहते हैं।

如果生产者放入元素的速度比消费者取出的速度快,无界 队列就会一直增长 — 直到内存耗尽。有界 队列(Queue(maxsize=N))满了时会让 put() 等待,生产者于是放慢到消费者的速度。这就叫 背压。

🚰 Simulator: Backpressure Lab🚰 Simulator: Backpressure Lab🚰 模拟器:背压实验室

Set how many items the producer adds per tick, how many the consumer removes, and the queue's maxsize. The blue line is the queue length over 30 ticks; red marks show ticks where the producer had to wait. The model was checked against a queue.Queue run with put_nowait() for all 36 settings.

तय कीजिए producer हर tick में कितने items डालता है, consumer कितने निकालता है, और queue का maxsize। नीली line 30 ticks में queue की लंबाई है; लाल निशान वे ticks हैं जहाँ producer को इंतज़ार करना पड़ा। Model को सभी 36 settings के लिए put_nowait() वाले queue.Queue run से जाँचा गया।

设置生产者每个时刻放入多少个元素、消费者取出多少个,以及队列的 maxsize。蓝线是 30 个时刻内的队列长度;红色标记表示生产者不得不等待的时刻。该模型已针对全部 36 种设置,与使用 put_nowait() 的 queue.Queue 运行结果核对。

Backpressure LabBackpressure Lab背压实验室36 settings checked36 settings जाँची已核对 36 种设置
Producer adds / tick:Producer डालता / tick:生产者每时刻放入:
Consumer removes / tick:Consumer निकालता / tick:消费者每时刻取出:
maxsize:
in the queuequeue में队列中
producedबनाए已生产
consumedइस्तेमाल हुए已消费
ticks the producer waitedproducer ने इंतज़ार किया (ticks)生产者等待的时刻数
🚦
maxsize Is a Free Rate Limitermaxsize मुफ़्त Rate Limiter हैmaxsize 就是免费的限流器

A maxsize turns the queue into a natural speed limit. When it is full, producers wait, so memory use stays flat no matter how fast work arrives.

maxsize queue को स्वाभाविक speed limit बना देता है। भरने पर producers इंतज़ार करते हैं, इसलिए काम कितना भी तेज़ आए, memory का इस्तेमाल स्थिर रहता है।

maxsize 让队列成为天然的限速器。满了时生产者会等待,所以无论任务来得多快,内存占用都保持平稳。


SectionSection第 13 节

Real-World Scenarios — Which Queue for What 🌍असली Scenarios — किस काम के लिए कौन-सी Queue 🌍真实场景 — 什么任务用什么队列 🌍

🕷️
Web CrawlerWeb Crawler网络爬虫
queue.Queue (FIFO)
URLs to visit form a FIFO queue. Several worker threads take URLs and add newly found links. Give it a maxsize so memory cannot explode.
देखने वाले URLs एक FIFO queue बनाते हैं। कई worker threads URLs लेते हैं और नए मिले links जोड़ते हैं। maxsize दीजिए ताकि memory न फटे।
待访问的 URL 组成一个 FIFO 队列。多个工作线程取出 URL,并加入新发现的链接。设置 maxsize,防止内存爆炸。
↩️
Undo / Redo HistoryUndo / Redo History撤销 / 重做历史
deque as a stackstack के रूप में deque用 deque 作栈
Each action is pushed on a stack; undo pops the last one. Redo needs a second stack. deque(maxlen=N) keeps only the last N actions.
हर action stack पर push होता है; undo आख़िरी वाला pop करता है। Redo के लिए दूसरा stack चाहिए। deque(maxlen=N) सिर्फ़ आख़िरी N actions रखता है।
每个操作压入栈中;撤销时弹出最后一个。重做需要第二个栈。deque(maxlen=N) 只保留最近 N 个操作。
🚨
Alert RouterAlert Router告警路由
PriorityQueue
Critical (P1) alerts must jump ahead of info (P4) alerts. A PriorityQueue shows the on-call engineer the worst problems first, whenever they arrived.
Critical (P1) alerts को info (P4) alerts से आगे जाना है। PriorityQueue on-call engineer को सबसे गंभीर समस्याएँ पहले दिखाती है, चाहे वे कभी भी आई हों।
严重(P1)告警必须排在信息类(P4)告警之前。PriorityQueue 让值班工程师先看到最严重的问题,不管它们何时到达。
🎧
Audio Streaming BufferAudio Streaming Buffer音频流缓冲
deque(maxlen=N)
A fixed number of audio frames in memory. When the player falls behind, new frames push out the oldest — a circular buffer.
Memory में audio frames की तय संख्या। Player पीछे रह जाए तो नए frames सबसे पुराने को बाहर कर देते हैं — एक circular buffer।
内存中保存固定数量的音频帧。播放器跟不上时,新帧会挤掉最旧的帧 — 这就是环形缓冲区。
🖥️
CPU-Heavy Batch JobCPU-Heavy Batch JobCPU 密集型批处理
multiprocessing.JoinableQueue
Spread tasks over several processes. A JoinableQueue with task_done() and join() tells you when all the work is finished.
Tasks को कई processes में बाँटिए। task_done() और join() वाली JoinableQueue बताती है कि सारा काम कब पूरा हुआ।
把任务分到多个进程。带 task_done() 和 join() 的 JoinableQueue 会告诉你所有工作何时完成。
🌐
Async Web ServerAsync Web Server异步 Web 服务
asyncio.Queue
Coroutines produce and consume messages without blocking the event loop. Use asyncio.Queue — never queue.Queue, whose blocking get() would freeze the loop.
Coroutines event loop को रोके बिना messages बनाते और इस्तेमाल करते हैं। asyncio.Queue लीजिए — queue.Queue कभी नहीं, जिसका blocking get() loop जमा देगा।
协程在不阻塞事件循环的情况下生产和消费消息。请用 asyncio.Queue — 绝不要用 queue.Queue,它会阻塞的 get() 会冻结事件循环。

SectionSection第 14 节

Practical Example — A Multi-Queue Task Scheduler 🗓️काम का Example — Multi-Queue Task Scheduler 🗓️实用示例 — 多队列任务调度器 🗓️

Three worker threads pull from three queues in strict priority order: emergency tasks first, then normal tasks, then background work.

तीन worker threads तीन queues से सख़्त priority क्रम में काम लेते हैं: पहले emergency tasks, फिर normal tasks, फिर background काम।

三个工作线程按严格的优先顺序从 三个队列 中取任务:先紧急任务,再普通任务,最后是后台任务。

from queue import Queue, Empty
import threading, time

emergency = Queue()
normal = Queue()
background = Queue()

def worker():
    while True:
        # Try each queue in priority order
        for name, q in [("emergency", emergency),
                        ("normal", normal),
                        ("bg", background)]:
            try:
                task = q.get_nowait()
            except Empty:              # only "this queue is empty"
                continue
            if task is None:
                return
            print(f"[{name}] processing {task}")
            time.sleep(0.1)
            break
        else:
            time.sleep(0.05)           # all empty, wait a bit

# Feed the tasks FIRST, then start the workers
for i in range(10): background.put(f"bg-{i}")
for i in range(5):  normal.put(f"task-{i}")
for i in range(2):  emergency.put(f"fire-{i}")

threads = [threading.Thread(target=worker) for _ in range(3)]
for t in threads: t.start()

time.sleep(2)
for _ in threads: emergency.put(None)   # one poison pill per worker
for t in threads: t.join()
OUTPUT
[emergency] processing fire-0[emergency] processing fire-1 [normal] processing task-0 [normal] processing task-1 [normal] processing task-2 [normal] processing task-3 [normal] processing task-4 [bg] processing bg-0 [bg] processing bg-1 [bg] processing bg-2 [bg] processing bg-3 [bg] processing bg-4 [bg] processing bg-5 [bg] processing bg-6 [bg] processing bg-7 [bg] processing bg-8 [bg] processing bg-9
🔧
Fixed: Three Problems in the Original Schedulerसुधार: मूल Scheduler की तीन समस्याएँ已修正:原调度器的三个问题

(1) It used a bare except:. That catches every error — a typo, a bug in your task, even Ctrl+C — and silently moves on. We catch only queue.Empty. (2) It started the workers before adding the tasks, so a fast worker could grab a background task before the emergencies arrived. In our runs it happened to work, but the order was luck; we feed the queues first. (3) Its output ended with "…", so it was not a real run. The output above is real.

(1) इसमें खुला except: था। यह हर error पकड़ लेता है — typo, आपके task का bug, यहाँ तक कि Ctrl+C — और चुपचाप आगे बढ़ जाता है। हम सिर्फ़ queue.Empty पकड़ते हैं। (2) इसने tasks जोड़ने से पहले workers शुरू किए, इसलिए कोई तेज़ worker emergencies आने से पहले background task उठा सकता था। हमारे runs में यह चल गया, पर क्रम क़िस्मत से था; हम पहले queues भरते हैं। (3) इसका output "…" पर ख़त्म होता था, यानी असली run नहीं था। ऊपर का output असली है।

(1) 它用了裸露的 except:。这会捕获 所有 错误 — 拼写错误、任务里的 bug,甚至 Ctrl+C — 然后悄悄继续。我们只捕获 queue.Empty。(2) 它在添加任务 之前 就启动了工作线程,所以一个快速的线程可能在紧急任务到来之前抢到后台任务。在我们的运行中碰巧没出问题,但顺序靠的是运气;我们改为先填充队列。(3) 它的输出以"…"结尾,并不是真实运行。上面的输出是真实的。


SectionSection第 15 节

Complete Comparison Table 📋पूरी तुलना Table 📋完整对比表 📋

ImplementationImplementation实现TypeType类型Thread-safeThread-safe线程安全Process-safeProcess-safe进程安全Blocking APIBlocking API阻塞 APISpeedगति速度
listLIFO stack onlyसिर्फ़ LIFO stack仅 LIFO 栈Noनहीं否*Noनहीं否Noनहीं否Fastestसबसे तेज़最快
collections.dequeFIFO / LIFO / Dequeappend/pop onlyसिर्फ़ append/pop仅 append/popNoनहीं否Noनहीं否Very fastबहुत तेज़很快
heapqPriority (min-heap)Priority (min-heap)优先级(最小堆)Noनहीं否Noनहीं否Noनहीं否Very fastबहुत तेज़很快
queue.QueueFIFOYesहाँ是Noनहीं否Yesहाँ是Mediumमध्यम中等
queue.LifoQueueLIFOYesहाँ是Noनहीं否Yesहाँ是Mediumमध्यम中等
queue.PriorityQueuePriorityPriority优先级Yesहाँ是Noनहीं否Yesहाँ是Medium (≈3× slower than heapq here)मध्यम (यहाँ heapq से ≈3× धीमा)中等(此处比 heapq 慢约 3 倍)
queue.SimpleQueueFIFO (unbounded)FIFO (असीमित)FIFO(无界)Yesहाँ是Noनहीं否Yes (get)हाँ (get)是(get)Fast (C code)तेज़ (C code)快(C 实现)
multiprocessing.QueueFIFOYesहाँ是Yesहाँ是Yesहाँ是Slow (pickling)धीमा (pickling)慢(需 pickle)
multiprocessing.JoinableQueueFIFO + task_doneYesहाँ是Yesहाँ是Yesहाँ是Slow (pickling)धीमा (pickling)慢(需 pickle)
asyncio.QueueFIFONoनहीं否Noनहीं否Yes (await)हाँ (await)是(await)Fast (in one loop)तेज़ (एक loop में)快(同一循环内)
asyncio.LifoQueueLIFONoनहीं否Noनहीं否Yes (await)हाँ (await)是(await)Fastतेज़快
asyncio.PriorityQueuePriorityPriority优先级Noनहीं否Noनहीं否Yes (await)हाँ (await)是(await)Fastतेज़快

* A single append() or pop() on a list is atomic in CPython, but a mix of steps from several threads (check, then pop) can still race.

* CPython में list पर एक अकेला append() या pop() atomic है, पर कई threads से कई क़दमों का मेल (पहले check, फिर pop) फिर भी टकरा सकता है।

* 在 CPython 中,对列表的单次 append() 或 pop() 是原子的,但多个线程的多步操作(先检查再弹出)仍可能产生竞争。

🔧
Fixed: "8 Implementations" and Speed Labelsसुधार: "8 Implementations" और Speed Labels已修正:"8 种实现"与速度标注

The intro promised "8 Python implementations", but this table lists 12. We also checked the speed labels: heapq was about 3× faster than PriorityQueue on our machine (100,000 push+pop), and SimpleQueue more than 10× faster than Queue (Section 08). The labels above now match those measurements.

शुरुआत में "8 Python implementations" का वादा था, पर यह table 12 बताती है। हमने speed labels भी जाँचे: हमारी machine पर heapq, PriorityQueue से लगभग 3× तेज़ था (100,000 push+pop), और SimpleQueue, Queue से 10× से ज़्यादा तेज़ (Section 08)। ऊपर के labels अब इन मापों से मेल खाते हैं।

开头承诺了"8 种 Python 实现",但这张表列出了 12 种。我们还核对了速度标注:在我们的机器上(100,000 次压入 + 弹出),heapq 比 PriorityQueue 快约 3 倍,SimpleQueue 比 Queue 快 10 倍以上(第 08 节)。上表的标注现已与这些测量结果一致。


SectionSection第 16 节

Which Queue Should I Use? 🧭कौन-सी Queue लूँ? 🧭我该用哪种队列?🧭

Answer three questions and the picker walks the decision for you — the interactive version of the original flowchart.

तीन सवालों के जवाब दीजिए और picker आपके लिए फ़ैसला कर देगा — मूल flowchart का interactive version।

回答三个问题,选择器会替你完成决策 — 这是原流程图的互动版。

Queue PickerQueue Picker队列选择器3 questions3 सवाल3 个问题
1. Who shares the queue?Queue कौन बाँटता है?谁来共享这个队列?
2. Which item should come out next?अगला कौन-सा item निकले?下一个应该取出哪个元素?
3. Do you need a size limit?Size limit चाहिए?需要容量限制吗?

SectionSection第 17 节

Bug Doctor, Golden Rules and Quiz 🏆Bug Doctor, सुनहरे नियम और Quiz 🏆Bug 医生、黄金法则与小测验 🏆

🩺 Simulator: Bug Doctor🩺 Simulator: Bug Doctor🩺 模拟器:Bug 医生

Six real queue mistakes. Buggy code on the left, fixed code on the right, changed lines marked. Every output is from a real run.

Queues की छह असली ग़लतियाँ। बाईं ओर buggy code, दाईं ओर ठीक किया हुआ, बदली lines चिह्नित। हर output असली run से है।

六个真实的队列错误。左边是有 bug 的代码,右边是修正后的代码,改动的行已标出。每个输出都来自真实运行。

Bug DoctorBug DoctorBug 医生6 bugs · real outputs6 bugs · असली outputs6 个 bug · 真实输出
❌ BuggyBuggy有 bug
✅ Fixedठीक किया已修正
🔑 Queue Types — Rules to RememberQueue Types — याद रखने वाले नियम队列类型 — 必须记住的规则
1
Never use a plain list as a FIFO. list.pop(0) is O(n) and gets slower as the list grows. Use collections.deque or queue.Queue.
सादी list को कभी FIFO की तरह मत लीजिए। list.pop(0) O(n) है और list बढ़ने पर धीमा होता जाता है। collections.deque या queue.Queue लीजिए।
绝不要把普通列表当 FIFO 用。list.pop(0) 是 O(n) 的,列表越长越慢。请用 collections.deque 或 queue.Queue。
2
A list is fine as a stack — append() and pop() at the end are both O(1). For a stack shared by threads, use queue.LifoQueue.
Stack के लिए list ठीक है — अंत पर append() और pop() दोनों O(1) हैं। Threads में बँटे stack के लिए queue.LifoQueue लीजिए।
列表当栈用没问题 — 在末尾 append() 和 pop() 都是 O(1)。多线程共享的栈请用 queue.LifoQueue。
3
Match the queue to the concurrency model: threads → queue module, processes → multiprocessing, asyncio → asyncio.Queue. Do not mix them.
Queue को concurrency model से मिलाइए: threads → queue module, processes → multiprocessing, asyncio → asyncio.Queue। इन्हें मिलाइए मत।
让队列与并发模型匹配:线程 → queue 模块,进程 → multiprocessing,asyncio → asyncio.Queue。不要混用。
4
Set maxsize on long-running queues. An unbounded queue grows without limit the moment producers are faster than consumers.
लंबे चलने वाली queues पर maxsize लगाइए। जिस पल producers consumers से तेज़ हों, असीमित queue बिना रुके बढ़ने लगती है।
长期运行的队列要设置 maxsize。一旦生产者比消费者快,无界队列就会无限增长。
5
For equal priorities, add a tie-breaker counter — (priority, next(counter), item) — or use @dataclass(order=True) with field(compare=False) on the data. Otherwise Python tries to compare the items and may raise TypeError.
बराबर priorities के लिए tie-breaker counter जोड़िए — (priority, next(counter), item) — या data पर field(compare=False) के साथ @dataclass(order=True) लीजिए। वरना Python items की तुलना करने की कोशिश करता है और TypeError आ सकता है।
优先级相同时,加一个打破平局的计数器 — (priority, next(counter), item) — 或者使用 @dataclass(order=True) 并在数据字段上设置 field(compare=False)。否则 Python 会尝试比较元素,可能抛出 TypeError。
6
Use deque(maxlen=N) for any "last N items" job — recent log lines, a rolling average, recent history. It is simpler than a full circular-queue class.
"आख़िरी N items" वाले हर काम के लिए deque(maxlen=N) लीजिए — हाल की log lines, rolling average, हाल का इतिहास। यह पूरी circular-queue class से आसान है।
任何"最近 N 个元素"的场景都用 deque(maxlen=N) — 最近的日志行、滚动平均、最近的历史记录。它比完整的循环队列类简单。
7
Prefer queue.SimpleQueue for simple thread hand-offs. It was more than 10× faster than Queue in our test, because it has no maxsize or task_done()/join().
सरल thread hand-offs के लिए queue.SimpleQueue चुनिए। हमारे test में यह Queue से 10× से ज़्यादा तेज़ था, क्योंकि इसमें maxsize या task_done()/join() नहीं है।
简单的线程交接优先用 queue.SimpleQueue。在我们的测试中它比 Queue 快 10 倍以上,因为它没有 maxsize 和 task_done()/join()。
8
Keep multiprocessing.Queue messages small. Every put()/get() pickles and copies the data. For big arrays, use multiprocessing.shared_memory and send only its name through the queue.
multiprocessing.Queue के messages छोटे रखिए। हर put()/get() data को pickle और copy करता है। बड़े arrays के लिए multiprocessing.shared_memory लीजिए और queue से सिर्फ़ उसका नाम भेजिए।
multiprocessing.Queue 的消息要小。每次 put()/get() 都会 pickle 并复制数据。大数组请用 multiprocessing.shared_memory,只通过队列传递它的名字。
9
If you use join(), call task_done() once for every get() — in a finally block. Otherwise one exception makes join() wait for ever.
अगर join() इस्तेमाल करते हैं, तो हर get() के लिए एक बार task_done() बुलाइए — finally block में। वरना एक exception join() को हमेशा इंतज़ार कराता है।
如果使用 join(),每次 get() 都要在 finally 块里调用一次 task_done()。否则一个异常就会让 join() 永远等下去。
10
Stop consumers with poison pills — one None per worker after the real work. It is cleaner than killing threads or processes.
Consumers को poison pills से रोकिए — असली काम के बाद हर worker के लिए एक None। यह threads या processes को मारने से ज़्यादा साफ़ है।
用"毒丸"停止消费者 — 真正的工作完成后,每个工作者放一个 None。这比强行杀死线程或进程更干净。
11
For single-threaded priority work, use heapq directly. It skips all the locking, and was about 3× faster than PriorityQueue in our test.
Single-thread priority काम के लिए सीधे heapq लीजिए। यह सारी locking छोड़ देता है, और हमारे test में PriorityQueue से लगभग 3× तेज़ था।
单线程的优先级任务直接用 heapq。它省掉了所有加锁的开销,在我们的测试中比 PriorityQueue 快约 3 倍。

Quick Quiz — 8 Questionsछोटा Quiz — 8 सवाल小测验 — 8 道题

🏆 QuizPick an answer to see why.जवाब चुनें और कारण देखें।选一个答案,看看原因。
🎯
Key Takeawayमुख्य सीख关键要点

First decide which item should come out next: oldest (FIFO → deque), newest (LIFO → list), most urgent (priority → heapq), either end (deque) or only the last N (deque(maxlen=N)). Then decide who shares it: threads → queue, processes → multiprocessing, coroutines → asyncio. Add a maxsize for backpressure, a counter for priority ties, and task_done() in finally when you join().

पहले तय कीजिए अगला कौन-सा item निकले: सबसे पुराना (FIFO → deque), सबसे नया (LIFO → list), सबसे ज़रूरी (priority → heapq), कोई भी सिरा (deque) या सिर्फ़ आख़िरी N (deque(maxlen=N))। फिर तय कीजिए इसे कौन बाँटता है: threads → queue, processes → multiprocessing, coroutines → asyncio। Backpressure के लिए maxsize, priority ties के लिए counter, और join() करते समय finally में task_done() जोड़िए।

先决定 下一个取出哪个元素:最早的(FIFO → deque)、最新的(LIFO → list)、最紧急的(优先级 → heapq)、任意一端(deque)或只保留最近 N 个(deque(maxlen=N))。再决定 谁来共享它:线程 → queue,进程 → multiprocessing,协程 → asyncio。用 maxsize 实现背压,用计数器打破优先级平局,使用 join() 时在 finally 中调用 task_done()。

🐍 Try Python Yourself

Write, run and visualize Python step by step. No install needed.

You have completed Queue. View all sections →