کتابخانه queue در پایتون
ماژول queue در پایتون ابزاری استاندارد و ساده برای مدیریت صفها در برنامههایی است که چند نخ (threads) دارند. این ماژول کلاسهایی ارائه میدهد که عملیات افزودن و برداشتن آیتم را بهصورت ایمن در برابر رقابت نخها (thread-safe) مدیریت میکنند و از قفلها و شرایط (locks and conditions) داخلی استفاده میکنند تا از بروز شرایط رقابتی جلوگیری شود.
کلاسهای اصلی در ماژول queue
- Queue — صف معمولی FIFO (اولین وارد، اولین خارج).
- LifoQueue — صف LIFO (مانند پشته، آخرین وارد، اولین خارج).
- PriorityQueue — صف با اولویت که عنصرها را بر اساس مقدار اولویت مرتب میکند.
- SimpleQueue — پیادهسازی ساده و سبک (از نسخههای جدید پایتون)، مناسب زمانی که نیاز به متدهای پیچیده نیست.
ویژگیها و متدهای پرکاربرد
- put(item, block=True, timeout=None) — افزودن آیتم، بهصورت مسدودکننده یا غیرمسدودکننده.
- get(block=True, timeout=None) — دریافت آیتم از صف.
- put_nowait(item) / get_nowait() — نسخههای غیرمسدودکننده.
- task_done() — اعلام انجام کار برای یک ایتم که از get گرفته شده؛ در ترکیب با join() استفاده میشود.
- join() — منتظر میماند تا همه آیتمهای صف پردازش شوند (تعداد task_done برابر با تعداد put).
- qsize(), empty(), full() — اطلاعات وضعیت صف؛ توجه: qsize/empty/full قابل اتکا در سناریوهای همزمان کامل نیستند (race conditions).
- استثناها: queue.Empty و queue.Full.
مثال عملی: تولیدکننده/مصرفکننده با Queue و task_done()
import threading
import queue
import time
def producer(q, count):
for i in range(count):
q.put(i)
print("Produced", i)
time.sleep(0.1)
# ارسال نشانه پایان
q.put(None)
def consumer(q):
while True:
item = q.get()
if item is None:
q.task_done()
break
print("Consumed", item)
time.sleep(0.2)
q.task_done()
q = queue.Queue()
t1 = threading.Thread(target=producer, args=(q, 10))
t2 = threading.Thread(target=consumer, args=(q,))
t1.start()
t2.start()
q.join()
t1.join()
t2.join()توضیح: این کد یک تولیدکننده دارد که اعداد را به صف اضافه میکند و در پایان مقدار None را به عنوان نشانۀ پایان ارسال میکند. مصرفکننده آیتمها را میخواند تا زمانی که None بگیرد. متدهای task_done() و join() برای همگامسازی استفاده شدهاند تا برنامه تا پایان پردازش منتظر بماند. استفاده از sentinel (اینجا None) راه استانداردی برای قطع مصرفکنندههاست.
نکات بهینهسازی
- از
qsize()برای منطق تصمیمگیری حساس به شرایط همزمان استفاده نکنید؛ ممکن است نادرست باشد. - برای لغو مصرفکنندههای متعدد، به ازای هر مصرفکننده یک sentinel ارسال کنید.
- برای ارسال بین پردازشها از
multiprocessing.Queueاستفاده کنید؛queue.Queueبرای نخها طراحی شده است.
نمونه: استفاده از PriorityQueue
import queue
pq = queue.PriorityQueue()
pq.put((2, "low priority"))
pq.put((0, "high priority"))
pq.put((1, "medium priority"))
while not pq.empty():
priority, item = pq.get()
print(priority, item)توضیح: PriorityQueue آیتمها را بر اساس کلید اول مرتب میکند. معمولترین الگو قرار دادن تاپل به شکل (priority, item) است تا از مقایسه مستقیم اشیاء جلوگیری شود. باید توجه کنید که اگر اولویتها برابر باشند و آیتمها قابل مقایسه نباشند، ممکن است خطای مقایسه رخ دهد؛ بنابراین ساختار تاپل امنترین روش است.
SimpleQueue و زمانبندی سبک
from queue import SimpleQueue
import threading
q = SimpleQueue()
def producer():
for i in range(3):
q.put(i)
def consumer():
while True:
try:
item = q.get()
print(item)
except Exception:
break
t1 = threading.Thread(target=producer)
t2 = threading.Thread(target=consumer)
t1.start()
t2.start()
t1.join()
# SimpleQueue هیچ task_done/join ای نداردتوضیح: SimpleQueue رابطی بسیار سادهتر ارائه میدهد و متدهای task_done و join را ندارد. برای سناریوهایی که به صف سبک و سریع نیاز دارید مناسب است. توجه داشته باشید که برای همگامسازی پیچیدهتر باید مکانیزمهای دیگری مثل Event یا sentinel به کار رود.
مقایسه سریع: queue vs alternatives
| ویژگی | queue.Queue | collections.deque | multiprocessing.Queue | asyncio.Queue |
|---|---|---|---|---|
| امنیت برای نخها | بله | نه بهطور خودکار | خیر (برای پروسسها طراحی شده) | خیر (برای async) |
| مناسب برای پردازشها | خیر | خیر | بله | خیر |
| پشتیبانی از join/task_done | بله | خیر | خیر | خیر |
اشتباهات متداول و نکات ایمنی
- استفاده از
q.get_nowait()بدون مدیریت استثناءqueue.Emptyمنجر به خطا میشود. - اعتماد به
qsize()برای تصمیمگیری همزمان میتواند باعث رقابت زمانبندی شود؛ بهتر است از قفلها یا مکانیزمهای همگامسازی دیگر استفاده کنید. - برای لغو امن نخها از sentinel یا مکانیزمهای همگامسازی استفاده کنید؛ نباید نخها را به زور متوقف کنید.
جمعبندی و توصیههای حرفهای
ماژول queue ابزار قابل اعتمادی برای طراحی الگوهای تولیدکننده/مصرفکننده در برنامههای چندنخی ارائه میدهد. با فهم متدهایی مثل put, get, task_done و join و توجه به محدودیتها و استثناها، میتوانید سیستمهای همگامشده و مقاوم بسازید. برای ارتباط بین پردازشها از ابزارهای مخصوص (مثل multiprocessing.Queue) و برای برنامههای غیرهمزمان از asyncio.Queue استفاده کنید.
آیا این مطلب برای شما مفید بود ؟





