DispatchQueue: چیست، صف GCD و مبانی چندنخی

نویسنده: IT Sectr منتشر شده: 2026-03-16 زمان مطالعه: 8 دقیقه

DispatchQueue یک صف بنیادین چارچوب Grand Central Dispatch (GCD) برای مدیریت وظایف ناهمگام در iOS و macOS است. به گفته Apple Developer Documentation, 2026، DispatchQueue مدیریت نخ‌ها را از طریق صف‌های serial و concurrent از توسعه‌دهنده انتزاع می‌کند. GCD به طور خودکار وظایف را در سراسر استخر نخ‌های سیستم توزیع می‌کند و نیاز به ایجاد و نابودی دستی نخ‌ها را از بین می‌برد.

نکات اصلی

  • DispatchQueue — انتزاع اصلی GCD برای اجرای ناهمگام کد در iOS
  • صف Serial وظایف را به صورت کاملاً متوالی اجرا می‌کند و شرایط رقابت را حذف می‌کند
  • صف Concurrent چندین وظیفه را به صورت موازی از طریق استخر نخ‌های سیستم اجرا می‌کند
  • QoS اولویت وظیفه را تعیین می‌کند — از userInteractive تا background
  • DispatchQueue.main — تنها صف برای به‌روزرسانی UIKit در نخ اصلی

DispatchQueue و Grand Central Dispatch چیست

DispatchQueue یک شی از چارچوب Grand Central Dispatch (GCD) است که اجرای وظایف را در صف‌های نخ سیستمی یا سفارشی مدیریت می‌کند. Grand Central Dispatch یک کتابخانه سطح پایین اپل است که از iOS 4 و macOS 10.6 در دسترس است و مدیریت نخ‌ها را کاملاً از توسعه‌دهنده انتزاع می‌کند. GCD از استخر نخ‌های سیستم عامل استفاده می‌کند و به طور خودکار تعداد نخ‌ها را بر اساس بار دستگاه مقیاس‌پذیر می‌کند.

توسعه‌دهنده نیازی به ایجاد و نابودی دستی نخ‌ها ندارد — GCD این وظیفه را بر عهده می‌گیرد و یک API ساده از طریق DispatchQueue ارائه می‌دهد. وظیفه به صورت closure (بستار) از طریق متدهای sync یا async به صف ارسال می‌شود. در حالت اول، نخ فراخوان تا پایان وظیفه مسدود می‌شود، در حالت دوم بلافاصله به اجرا ادامه می‌دهد.

به گفته اپل (2026)، GCD از استخر نخ سیستم استفاده می‌کند که با تعداد هسته‌ها و بار فعلی پردازنده سازگار می‌شود. صف concurrent برای هر وظیفه یک نخ جدید ایجاد نمی‌کند — GCD نخ‌ها را از استخر مجدداً استفاده می‌کند که هزینه‌های سربار ایجاد نخ را به حداقل می‌رساند.

معماری GCD

Grand Central Dispatch از سه مؤلفه کلیدی تشکیل شده است: صف (DispatchQueue)، گروه (DispatchGroup) و سمافور (DispatchSemaphore). صف عنصر اصلی است که وظایف را به صورت بلوک‌های کد دریافت می‌کند. DispatchGroup اجرای چندین وظیفه را همگام‌سازی می‌کند و DispatchSemaphore دسترسی به یک منبع مشترک را به تعداد مشخصی از نخ‌ها محدود می‌کند.

هر صف GCD با یک کلاس QoS (Quality of Service) خاص مرتبط است که به سیستم در مورد اهمیت وظیفه اطلاع می‌دهد. سیستم از QoS برای توزیع زمان پردازنده بین صف‌ها استفاده می‌کند و به وظایف بحرانی‌تر — مانند به‌روزرسانی UI یا پردازش لمس کاربر — اولویت می‌دهد.

صف‌های Serial و Concurrent: مقایسه

صف Serial وظایف را به صورت کاملاً متوالی، یکی پس از دیگری اجرا می‌کند. اگر سه وظیفه در صف serial قرار داده شود، دومی فقط پس از اتمام کامل اولی شروع می‌شود. صف‌های serial برای همگام‌سازی دسترسی به منابع مشترک استفاده می‌شوند — مثلاً آرایه‌ای که از چند بخش کد تغییر می‌کند.

صف Concurrent چندین وظیفه را همزمان اجرا می‌کند و آنها را بین نخ‌های موجود از استخر سیستم توزیع می‌کند. وظایف در صف concurrent به ترتیب ورود (FIFO) شروع می‌شوند، اما اگر زمان اجرای آنها متفاوت باشد، به ترتیب دلخواه به پایان می‌رسند. صف Concurrent ترتیب پایان را تضمین نمی‌کند — فقط ترتیب شروع را تضمین می‌کند.

پارامترصف Serialصف Concurrent
ترتیب اجراکاملاً متوالیموازی
تعداد نخ‌هایکچندین از استخر GCD
کاربردحفاظت از منابع مشترکمحاسبات مستقل
Main queueبله (نخ اصلی)خیر
ریسک Deadlockبالا در sync روی همان صفکم

چه زمانی صف serial را انتخاب کنیم

صف serial برای وظایفی که وضعیت مشترک را تغییر می‌دهند ایده‌آل است — نوشتن در فایل، به‌روزرسانی مدل داده یا کار با Core Data. استفاده از صف serial تضمین می‌کند که دو بخش کد همزمان داده‌های یکسانی را تغییر نمی‌دهند و شرایط رقابت را بدون قفل‌های اضافی حذف می‌کند.

چه زمانی صف concurrent را انتخاب کنیم

صف Concurrent برای وظایفی که به یکدیگر وابسته نیستند مناسب است: بارگذاری چندین تصویر، درخواست‌های شبکه موازی یا پردازش دسته‌ای داده‌ها. GCD به طور خودکار تصمیم می‌گیرد که چند وظیفه همزمان بر اساس تعداد هسته‌های پردازنده و بار فعلی سیستم اجرا شود.

Quality of Service: اولویت‌های اجرای وظایف

QoS (Quality of Service) — مکانیزم GCD که به سیستم عامل در مورد اهمیت و فوریت وظیفه اطلاع می‌دهد. سیستم از QoS برای برنامه‌ریزی نخ‌ها استفاده می‌کند: وظایف با QoS بالاتر زمان پردازنده بیشتری دریافت می‌کنند و زودتر اجرا می‌شوند. مقدار QoS هنگام ایجاد صف یا ارسال وظیفه خاص منتقل می‌شود.

در GCD پنج کلاس QoS موجود است. .userInteractive — بالاترین اولویت برای وظایف مرتبط با UI. .userInitiated — برای وظایف آغاز شده توسط کاربر. .utility — برای وظایف پس‌زمینه با نمایش پیشرفت. .background — برای وظایف نامرئی برای کاربر. .default — سطح میانی بین userInitiated و utility، به طور پیش‌فرض استفاده می‌شود.

به گفته اپل (2026)، انتخاب نادرست QoS یکی از دلایل رایج مشکلات عملکرد است. اجرای بارگیری پس‌زمینه با QoS .userInteractive منابع را از UI می‌گیرد و باعث میکرو لگ در انیمیشن‌ها می‌شود. توصیه می‌شود پایین‌ترین QoS را انتخاب کنید که همچنان زمان اجرای قابل قبولی را فراهم می‌کند.

مثال کاربرد QoS

هنگام بارگیری تصویر برای نمایش فوری از .userInitiated استفاده کنید — کاربر انتظار نتیجه را دارد. برای پیش‌بارگیری صفحه بعد، .utility کافی است. همگام‌سازی پس‌زمینه با سرور با .background اجرا می‌شود و تأثیر بر وظایف فعال را به حداقل می‌رساند.

DispatchGroup و سمافورها: همگام‌سازی وظایف

DispatchGroup امکان ردیابی اتمام یک گروه از وظایف را فراهم می‌کند. وقتی همه وظایف در گروه کامل شدند، GCD هندلر notify را در صف مشخص شده فراخوانی می‌کند. این به ویژه هنگام بارگیری چندین منبع مستقل — داده‌های پروفایل، لیست دوستان و تنظیمات — مفید است، زمانی که رابط باید فقط پس از دریافت همه داده‌ها به‌روزرسانی شود.

DispatchGroup از فراخوان همگام wait() پشتیبانی می‌کند که نخ فعلی را تا اتمام همه وظایف مسدود می‌کند. این زمانی راحت است که کد نمی‌تواند بدون نتایج گروه ادامه یابد. نسخه ناهمگام — notify() — پس از اتمام همه وظایف، closure را در صف مشخص شده فراخوانی می‌کند بدون اینکه نخ فراخوان را مسدود کند.

DispatchSemaphore برای محدود کردن همزمانی

DispatchSemaphore دسترسی به یک منبع را کنترل می‌کند و تعداد دسترسی‌های همزمان را محدود می‌کند. سمافور با مقدار اولیه 3 اجازه اجرای حداکثر سه وظیفه موازی را می‌دهد. هنگام فراخوانی wait() شمارنده کاهش می‌یابد، هنگام signal() افزایش می‌یابد. اگر شمارنده صفر باشد، نخ تا آزاد شدن منبع مسدود می‌شود.

نمونه کدهای DispatchQueue در Swift

سه مثال عملی استفاده از DispatchQueue در Swift را بررسی می‌کنیم. اولین مورد فراخوان پایه async با بازگشت به نخ اصلی را نشان می‌دهد، دومین — همگام‌سازی از طریق صف serial، سومین — DispatchGroup برای درخواست‌های موازی.

فراخوان پایه async با بازگشت به main

DispatchQueue.main — صف serial نخ اصلی است که منحصراً برای عملیات UI در نظر گرفته شده است. همیشه از آن برای به‌روزرسانی رابط پس از اتمام کار پس‌زمینه استفاده کنید.

swift
let queue = DispatchQueue.global(qos: .userInitiated)
queue.async {
    let data = self.fetchData()
    DispatchQueue.main.async {
        self.updateUI(with: data)
    }
}

صف serial برای حفاظت از منبع مشترک

ایجاد صف serial خود با شناسه منحصربه‌فرد، دسترسی به آرایه قابل تغییر را همگام‌سازی می‌کند. تمام عملیات خواندن و نوشتن از یک صف عبور می‌کنند و شرایط رقابت را حذف می‌کنند.

swift
let serialQueue = DispatchQueue(label: "com.app.items")
var items: [Int] = []

serialQueue.async {
    items.append(1)
}
serialQueue.async {
    let last = items.last
    DispatchQueue.main.async {
        print("Last item: \(last)")
    }
}

DispatchGroup برای درخواست‌های موازی

DispatchGroup امکان اجرای چندین وظیفه در صف concurrent و دریافت اعلان اتمام همه آنها را فراهم می‌کند. این برای بارگیری داده‌های صفحه پروفایل مفید است.

swift
let group = DispatchGroup()
let worker = DispatchQueue.global()

worker.async(group: group) { self.loadProfile() }
worker.async(group: group) { self.loadFriends() }
worker.async(group: group) { self.loadSettings() }

group.notify(queue: DispatchQueue.main) {
    self.showCompleteUI()
}

خطاهای رایج هنگام کار با DispatchQueue

Deadlock هنگام فراخوان sync در صف serial — رایج‌ترین خطا. اگر وظیفه‌ای در صف serial queue.sync را روی همان صف فراخوانی کند، نخ برای همیشه مسدود می‌شود. صف منتظر اتمام وظیفه فعلی است و وظیفه منتظر اتمام فراخوان sync — یک بن‌بست کلاسیک متقابل.

به‌روزرسانی UI از نخ پس‌زمینه

تمام عملیات با UIKit باید در نخ اصلی انجام شود. Xcode این خطاها را در حالت Debug از طریق Main Thread Checker شناسایی می‌کند. در نسخه Release، آنها منجر به رفتار غیرقابل پیش‌بینی می‌شوند: انیمیشن‌ها اجرا نمی‌شوند، UI به‌روزرسانی نمی‌شود، کرش ممکن است.

ایجاد بیش از حد صف‌های سفارشی

ایجاد صدها صف سفارشی به جای صف‌های جهانی — ضدالگو. هر صف منابع سیستم را مصرف می‌کند. برای بیشتر وظایف، صف‌های concurrent جهانی با QoS مختلف و یکی دو صف serial برای همگام‌سازی داده‌های مشترک کافی است.

نادیده گرفتن autoreleasepool در حلقه‌ها

هنگام اجرای وظایف چرخه‌ای منابعنگار در صف پس‌زمینه بدون autoreleasepool، حافظه تا پایان کل حلقه رشد می‌کند. ARC اشیاء را فقط هنگام خروج از autorelease pool آزاد می‌کند. تکرارهای حلقه را برای آزادسازی به‌موقع حافظه در autoreleasepool { } قرار دهید.

سوالات متداول

تفاوت بین DispatchQueue و OperationQueue چیست؟

OperationQueue بر روی GCD ساخته شده است اما API سطح بالاتری با وابستگی‌های عملیات، KVO و پشتیبانی از لغو ارائه می‌دهد. DispatchQueue یک صف سطح پایین برای وظایف ساده async بدون مدیریت وابستگی است.

آیا می‌توان وظیفه‌ای را در DispatchQueue به زور متوقف کرد؟

GCD از توقف وظیفه در حال اجرا پشتیبانی نمی‌کند. متد suspend() فقط وظایف جدید را متوقف می‌کند، وظیفه فعلی تا پایان اجرا می‌شود. برای لغو، بررسی دستی پرچم در داخل کد وظیفه لازم است.

چه QoS را برای درخواست شبکه انتخاب کنیم؟

برای درخواست اصلی با نمایش فوری نتیجه — .userInitiated. برای پیش‌بارگیری داده‌ها — .utility. برای همگام‌سازی پس‌زمینه — .background.

صف concurrent از چند نخ استفاده می‌کند؟

GCD تعداد نخ‌ها را ثابت نمی‌کند. استخر نخ‌ها به صورت پویا تحت بار مقیاس‌پذیر می‌شود و هسته‌های پردازنده، بار فعلی و QoS هر وظیفه را در نظر می‌گیرد. حداکثر تعداد توسط سیستم محدود می‌شود.

چرا DispatchQueue.main برای UIKit اجباری است؟

UIKit thread-safe نیست — تمام کلاس‌های آن باید فقط از نخ اصلی فراخوانی شوند. نقض باعث رفتار غیرقابل پیش‌بینی، به‌روزرسانی‌های از دست رفته و کرش در Production می‌شود.

خلاصه

  • DispatchQueue — ابزار اصلی Grand Central Dispatch برای وظایف ناهمگام در iOS و macOS
  • صف Serial وظایف را متوالی اجرا می‌کند و شرایط رقابت را بدون قفل حذف می‌کند
  • صف Concurrent وظایف را به صورت موازی از طریق استخر نخ سیستم اجرا می‌کند
  • QoS اولویت وظیفه را تعیین می‌کند — از userInteractive تا background
  • DispatchGroup چندین وظیفه موازی را با notify در نخ اصلی همگام‌سازی می‌کند
  • Deadlock هنگام sync در صف serial مشغول — خطای بحرانی نیازمند توجه
  • Main thread برای UIKit اجباری است — رابط را فقط از طریق DispatchQueue.main به‌روزرسانی کنید

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید