مقالات

انواع dispatchers ها در coroutines

انواع dispatchers ها در coroutines، با استفاده از آنها می‌توانید همروندی در برنامه‌های خود را بهبود بخشید و عملیات‌های مختلف را در نخ‌های مختلف اجرا کنید. با دیسپچرهای مختلف مانند Default ، IO و Main ، قابلیت کنترل و بهینه‌سازی اجرای عملیات‌های همروند را دارید تا برنامه‌ی خود را بهبود بخشید و بهتر به نیازهای خاص خود پاسخ دهید.

 

 

“ما را در اینستاگرام دنبال کنید”

در این مقاله از سری مقالات کاتلین اومدیم در مورد انواع dispatchers ها در coroutines صحبت کنیم. پس با سایت ترولرن همراه باش.

“قبل از شروع مقاله، بگم که بعد از مطالعه این مطلب، از آموزش پروژه محور برنامه نویسی اندروید سایتمون یعنی دوره ژنرال اندروید غافل نشید.”

توی دوره ژنرال صفر تا صد زبان انواع dispatchers ها رو در فصل coroutines کامل توضیح دادیم و همچنین توی پروژه های دیجی کالا و اسنپ فود به صورت عملی و پروژه محور از انواع dispatchers ها استفاده کردیم و بطور کامل اون رو آموزش دادیم.

dispatchers چیست؟

در برنامه‌نویسی همزمانی (concurrency) و مدیریت نخ‌ها، dispatchers نقش مهمی را ایفا می‌کنند. یک dispatcher مسئول تخصیص و مدیریت نخ‌ها و منابع موجود در سیستم برای اجرای وظایف مختلف است. در اصل، dispatcher مسئول تعیین این است که یک وظیفه (task) به کدام نخ اجرا شود و چگونه اجرا شود.

در زبان‌ها و فریمورک‌های مختلف، مفهوم dispatchers با نام‌ها و ویژگی‌های متفاوتی مطرح می‌شود. به طور کلی، یک dispatcher می‌تواند شامل مجموعه‌ای از نخ‌ها باشد که برای پردازش وظایف موازی استفاده می‌شوند. از dispatcher برای تخصیص وظایف به نخ‌ها، مدیریت ترتیب اجرا، اجرای چند وظیفه به صورت همزمان و مدیریت منابع مورد نیاز استفاده می‌شود.

در برنامه‌نویسی همزمان، dispatchers معمولاً به صورت چندسری (multithreaded) عمل می‌کنند و به وظایف راه‌اندازی شده توسط برنامه‌نویس اجازه می‌دهند تا به صورت همزمان اجرا شوند. Dispatchers می‌توانند مدیریت تقسیم بار بین نخ‌ها، اجرای وظایف درزمان‌های مختلف و کنترل همروندی و همسانگردی را بر عهده بگیرند.

از dispatchers مختلف می‌توان در کاربردهای مختلفی استفاده کرد، از جمله برنامه‌نویسی وب، برنامه‌نویسی رابط کاربری (UI)، پردازش داده‌های موازی و غیره. هر زبان برنامه‌نویسی و فریمورک ممکن است نوع و روش‌های متفاوتی برای مدیریت dispatchers داشته

باشد.

لطفاً توجه داشته باشید که توضیحات بالا به طور کلی در مورد مفهوم dispatchers در برنامه‌نویسی چندریختی بوده است و برای هر زبان برنامه‌نویسی و فریمورک خاص، رویکردها و مفاهیم دقیق‌تری وجود دارد.

انواع dispatchers ها

در برنامه‌نویسی با استفاده از کروتین‌ها، dispatchers نقش مهمی در مدیریت و اجرای کروتین‌ها دارند. Dispatchers مسئول تخصیص کروتین‌ها به نخ‌های موجود در سیستم عامل هستند. در Kotlin، چندین نوع dispatcher موجود است که هرکدام ویژگی‌ها و کاربردهای خاص خود را دارند. در زیر توضیحاتی درباره انواع مختلف dispatchers در کروتین‌ها آمده است:

  • Default Dispatcher

دیسپچر پیش‌فرض است که در صورتی که به صورت صریح dispatcher خاصی تعیین نکنید، استفاده می‌شود. این dispatcher از نخ‌های موجود در سیستم عامل برای اجرای کروتین‌ها استفاده می‌کند. به طور کلی، مناسب برای کاربردهای عمومی است و به خوبی با تعدادی کروتین کار می‌کند. اگر در مورد دیسپچر استفاده شده برای یک کروتین خاص اطلاعی نداشته باشید، احتمالاً از این دیسپچر استفاده شده است.

  • Unconfined Dispatcher

دیسپچر غیرمحدود (Unconfined) کروتین‌ها را بدون محدودیت اجرا می‌کند. این به این معنی است که اجرای کروتین در این دیسپچر به نخ‌های خاصی محدود نمی‌شود و ممکن است بین نخ‌های مختلف تغییر کند. این دیسپچر در مواقعی که نیاز به پردازش سبک و سریع دارید، مفید است. برای مثال، اگر یک کروتین نیاز به دسترسی به متغیرهای مشترک (shared variable) داشته‌باشد و نیازی به حفظ ترتیب اجرای آن نباشد، می‌توانید از این دیسپچر استفاده کنید.

  • IO Dispatcher

دیسپچر ورودی/خروجی (IO) برای عملیات ورودی/خروجی مانند خواندن و نوشتن فایل‌ها یا درخواست‌های شبکه مناسب است. این دیسپچر از نخ‌های خاصی که برای عملیات ورودی/خروجی بهینه‌سازی شده‌اند، استفاده می‌کند. با استفاده از این دیسپچر، عملیات ورودی/خروجی را می‌توانید به صورت کارآمد و بدون ایجاد بار زیاد بر سیستم انجام دهید.

  • Main Dispatcher

دیسپچر اصلی (Main) برای اجرای کروتین‌ها در رابط کاربری (UI) استفاده می‌شود. این دیسپچر کروتین‌ها را در نخ رابط کاربری اجرا می‌کند که برای تعامل با عناصر رابط کاربری مانند بروزرسانی عناصر UI مناسب است. این دیسپچر برای اجرای کروتین‌ها درمحیط‌هایی مانند اپلیکیشن‌های موبایل یا رابط کاربری وب بسیار مفید است.

 

 

برای درک بهتر هر کدام از dispatchers ها یک مثال با کاتلین میزنم

Default Dispatcher

فرض کنید که شما یک برنامه کاتلین دارید که در آن یک عملیات پردازش محاسباتی طولانی مدت وجود دارد. با استفاده از دیسپچر پیش‌فرض، می‌توانید این عملیات را به صورت همزمان در چند نخ اجرا کنید تا زمان اجرا کاهش یابد و برنامه شما به طور کلی پاسخگوتر شود. به طور مثال:

import kotlinx.coroutines.*

fun main() {
    runBlocking {
        val result = withContext(Dispatchers.Default) {
            // عملیات پردازش محاسباتی طولانی مدت
            calculateResult()
        }
        println("Result: $result")
    }
}

suspend fun calculateResult(): Int {
    delay(2000) // تاخیر مصنوعی برای شبیه‌سازی یک عملیات پردازش محاسباتی
    return 42
}
```

در این مثال، با استفاده از دیسپچر پیش‌فرض (Dispatchers.Default)، عملیات `calculateResult()` در یک نخ جداگانه اجرا می‌شود و برنامه ادامه می‌یابد. سپس پس از اتمام عملیات، نتیجه به صفحه خروجی چاپ می‌شود.

Unconfined Dispatcher

فرض کنید که شما یک برنامه کاتلین دارید که نیاز به دسترسی همزمان به منابع مشترک دارد، مانند یک متغیر به اشتراک گذاشته شده. در این مورد، از دیسپچر غیرمحدود (Unconfined) می‌توانید استفاده کنید تا کروتین به صورت همزمان در نخ‌های مختلف اجرا شود و محدودیت‌های مربوط به ترتیب اجرا را نداشته باشد. به طور مثال:

import kotlinx.coroutines.*

var sharedValue = 0

fun main() {
    runBlocking {
        withContext(Dispatchers.Unconfined) {
            launch {
                sharedValue = 42
                println("Value set in thread: ${Thread.currentThread().name}")
            }
            launch {
                println("Value read in thread: ${Thread.currentThread().name}")
                println("Shared value: $sharedValue")
            }
        }
    }
}
```

در این مثال، با استفاده از دیسپچر غیرمحدود (Dispatchers.Unconfined)، دو کروتین در نخ‌های جداگانه اجرا می‌شوند. متغیر `sharedValue` به صورت همزمان توسط کروتین‌ها دسترسی دارد و نیازی به ترتیب اجرا ندارد. این مثال نشان می‌دهد که خواندن و نوشتن به متغیر به صورت همزمان انجام می‌شود.

IO Dispatcher

اگر شما در برنامه‌ای نیاز به انجام عملیات ورود/خروج (I/O) دارید، می‌توانید از دیسپچر IO استفاده کنید. این دیسپچر بهینه شده برای عملیات‌های ورودی/خروجی است و معمولاً برای عملیاتی مانند خواندن/نوشتن فایل‌ها، اتصال به پایگاه داده، دریافت اطلاعات از شبکه و غیره استفاده می‌شود. به طور مثال

import kotlinx.coroutines.*
import java.io.File

fun main() {
    runBlocking {
        withContext(Dispatchers.IO) {
            launch {
                val fileContents = readFile("example.txt")
                println("File contents: $fileContents")
            }
            launch {
                writeFile("output.txt", "Hello, Dispatchers.IO!")
                println("File written successfully")
            }
        }
    }
}

suspend fun readFile(filename: String): String = withContext(Dispatchers.IO) {
    File(filename).readText()
}

suspend fun writeFile(filename: String, content: String) = withContext(Dispatchers.IO) {
    File(filename).writeText(content)
}
```

در این مثال، با استفاده از دیسپچر IO (Dispatchers.IO)، دو کروتین برای خواندن و نوشتن فایل‌ها به صورت همزمان اجرا می‌شوند. توابع `readFile` و `writeFile` از دیسپچر IO برای انجام عملیات ورودی/خروجی استفاده می‌کنند.

Main Dispatcher

در مثال زیر، فرض کنید که شما یک برنامه کاتلین دارید که نیاز به بروزرسانی واسط کاربری دارد، و این بروزرسانی باید در نخ اصلی انجام شود. در این صورت، از دیسپچر Main استفاده می‌کنید:

import kotlinx.coroutines.*
import java.util.concurrent.TimeUnit

fun main() {
    runBlocking {
        withContext(Dispatchers.Main) {
            launch {
                // شبیه‌سازی عملیات طولانی مدت
                delay(TimeUnit.SECONDS.toMillis(2))
                updateUI("Hello from coroutine!")
            }
            
            // ادامه کد در نخ اصلی
            println("Doing some other work in the main thread...")
        }
    }
}

fun updateUI(message: String) {
    // کد بروزرسانی واسط کاربری در این قسمت قرار می‌گیرد
    println("UI updated: $message")
}

در این مثال، با استفاده از دیسپچر Main (Dispatchers.Main)، کروتینی ایجاد می‌شود که یک تاخیر ۲ ثانیه‌ای دارد و پس از آن واسط کاربری را بروزرسانی می‌کند. در حین اجرای تاخیر، کد بعدی در نخ اصلی ادامه می‌یابد و پیام “Doing some other work in the main thread…” چاپ می‌شود.

با استفاده از دیسپچر Main، مطمئن می‌شوید که کد کروتین در نخ اصلی اجرا می‌شود و می‌توانید به راحتی به عملیات واسط کاربری دسترسی داشته باشید.به طور کلی، در کاتلین و کتابخانه کروتین (Coroutine) از dispatchers مختلف برای مدیریت همروندی در برنامه‌ها استفاده می‌شود. هر کدام از این dispatchers وظایف و محدودیت‌های مختلفی دارند و باید بر اساس نیازهای برنامه‌ی خود از مناسب‌ترین dispatcher استفاده کنید.

 

و همچنین ممنون میشم از طریق ستاره‌های این پایین به این مقاله امتیاز بدی و اگه هر سوالی داشتی توی قسمت دیدگاه بپرس و قطعا بهت پاسخ میدیم.

 

‫5/5 ‫(2 نظر)
عاطفه امیری

Recent Posts

بهینه‌سازی عملکرد اپلیکیشن‌های اندروید: راهنمای جامع و کاربردی

بهینه‌سازی عملکرد اپلیکیشن‌های اندروید یکی از مهم‌ترین فاکتورهایی است که برای کاربران در دنیای امروز…

4 ماه ago

سوالات مصاحبه‌ی استخدامی کاتلین همراه با جواب(قسمت چهارم)

مصاحبه‌ی استخدامی کاتلین یک فرصت برای ارزیابی مهارت‌ها و توانایی‌های یک برنامه‌نویس در توسعه اپلیکیشن‌های…

4 ماه ago

سوالات مصاحبه استخدام زبان کاتلین همراه با جواب(قسمت سوم)

مصاحبه استخدام زبان کاتلین یک فرصت برای ارزیابی مهارت‌ها و توانایی‌های یک برنامه‌نویس در توسعه…

4 ماه ago

سوالات مصاحبه استخدام کاتلین همراه با جواب(قسمت دوم)

مصاحبه استخدام کاتلین یک فرصت برای ارزیابی مهارت‌ها و توانایی‌های یک برنامه‌نویس در توسعه اپلیکیشن‌های…

5 ماه ago

سوالات مصاحبه استخدامی کاتلین همراه با جواب(قسمت اول)

مصاحبه استخدامی کاتلین یک فرصت برای ارزیابی مهارت‌ها و توانایی‌های یک برنامه‌نویس در توسعه اپلیکیشن‌های…

5 ماه ago

نوتیفیکیشن در اندروید: نحوه کار با آن در کاتلین

نوتیفیکیشن در اندروید امروزه یکی از قابلیت‌های مهم و پرکاربرد در اپلیکیشن‌های اندروید هستند. با…

5 ماه ago