ویژگی تصویر

معرفی کتابخانه queue در پایتون

  /  پایتون   /  کتابخانه 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.Queuecollections.dequemultiprocessing.Queueasyncio.Queue
امنیت برای نخ‌هابلهنه به‌طور خودکارخیر (برای پروسس‌ها طراحی شده)خیر (برای async)
مناسب برای پردازش‌هاخیرخیربلهخیر
پشتیبانی از join/task_doneبلهخیرخیرخیر

اشتباهات متداول و نکات ایمنی

  • استفاده از q.get_nowait() بدون مدیریت استثناء queue.Empty منجر به خطا می‌شود.
  • اعتماد به qsize() برای تصمیم‌گیری هم‌زمان می‌تواند باعث رقابت زمان‌بندی شود؛ بهتر است از قفل‌ها یا مکانیزم‌های همگام‌سازی دیگر استفاده کنید.
  • برای لغو امن نخ‌ها از sentinel یا مکانیزم‌های همگام‌سازی استفاده کنید؛ نباید نخ‌ها را به زور متوقف کنید.

جمع‌بندی و توصیه‌های حرفه‌ای

ماژول queue ابزار قابل اعتمادی برای طراحی الگوهای تولیدکننده/مصرف‌کننده در برنامه‌های چندنخی ارائه می‌دهد. با فهم متدهایی مثل put, get, task_done و join و توجه به محدودیت‌ها و استثناها، می‌توانید سیستم‌های همگام‌شده و مقاوم بسازید. برای ارتباط بین پردازش‌ها از ابزارهای مخصوص (مثل multiprocessing.Queue) و برای برنامه‌های غیرهمزمان از asyncio.Queue استفاده کنید.

آیا این مطلب برای شما مفید بود ؟

خیر
بله
موضوعات شما در انجمن: