Suspend function ایک ایسا فنکشن ہے جس میں suspend موڈیفائر ہوتا ہے جو تھریڈ کو بلاک کیے بغیر اپنی عملدرآمد روک سکتا ہے اور بعد میں اسی coroutine میں دوبارہ شروع کر سکتا ہے۔ JetBrains Kotlin Docs, 2025 کے مطابق، suspend فنکشنز coroutines کا بنیادی تعمیراتی بلاک ہیں، جو کال بیک کے بغیر غیر ہم آہنگی فراہم کرتے ہیں۔ ہر suspend فنکشن Continuation پر مبنی اسٹیٹ مشین میں مرتب ہوتا ہے، جو معطلی پوائنٹس کے موثر انتظام کی اجازت دیتا ہے۔
اہم نکات
Suspend function ایک ایسا فنکشن ہے جسے suspend کیورڈ کے ساتھ اعلان کیا گیا ہے جو تھریڈ کو بلاک کیے بغیر ایک یا زیادہ پوائنٹس پر عملدرآمد روک سکتا ہے۔ دوسرے suspend فنکشن کے اندر suspend فنکشن کی ہر کال ایک ممکنہ معطلی پوائنٹ ہے۔
suspend fun fetchUserData(): User {
val response = httpClient.get("/user")
return parser.parse(response)
}
Kotlin کمپائلر اس طرح کے فنکشن کو اسٹیٹ مشین میں ترجمہ کرتا ہے۔ ہر معطلی پوائنٹ (دوسرے suspend فنکشن کی کال) ایک اسٹیٹ (label) بن جاتا ہے۔ موجودہ تھریڈ اسٹیٹس کے درمیان جاری ہوتا ہے، اور منتظر آپریشن مکمل ہونے کے بعد، عملدرآمد اگلے اسٹیٹ سے دوبارہ شروع ہوتا ہے۔
suspend فنکشنز Kotlin 1.3 (2018) میں coroutines کے ساتھ ایک تجرباتی فیچر کے طور پر ظاہر ہوئے اور Kotlin 1.5 (2021) میں مستحکم ہو گئے۔ اس سے پہلے، Kotlin/Java میں غیر ہم آہنگی کال بیک، RxJava اور CompletableFuture کے ذریعے حاصل کی جاتی تھی۔ suspend فنکشنز نے لکیری نحو اور خودکار تھریڈ مینجمنٹ کے ساتھ ایک متبادل پیش کیا۔
suspend فنکشنز کی داخلی کارروائی کو سمجھنا coroutines کے ساتھ صحیح طریقے سے کام کرنے کی کلید ہے۔ عام فنکشنز کے برعکس، ہر suspend فنکشن Continuation انٹرفیس کے ساتھ ایک کلاس میں مرتب ہوتا ہے۔
Kotlin کمپائلر ہر suspend فنکشن کے پیرامیٹر کی فہرست کے آخر میں Continuation قسم کا ایک پیرامیٹر شامل کرتا ہے۔ Continuation میں شامل ہے:
فرض کریں کہ ہمارے پاس دوسرے suspend فنکشنز کی دو کالوں والا ایک suspend فنکشن ہے:
suspend fun process() {
val a = stepOne()
val b = stepTwo(a)
println(b)
}
کمپائلر اسے لیبلز کے ساتھ اسٹیٹ مشین میں تبدیل کرتا ہے:
// Simplified generated code representation
fun process(cont: Continuation<Unit>): Any? {
val cont = cont as ProcessContinuation
when (cont.label) {
0 -> {
cont.label = 1
if (stepOne(cont) == COROUTINE_SUSPENDED) return COROUTINE_SUSPENDED
}
1 -> {
cont.label = 2
val a = cont.result as TypeA
if (stepTwo(a, cont) == COROUTINE_SUSPENDED) return COROUTINE_SUSPENDED
}
2 -> {
println(cont.result)
Unit
}
}
}
اہم مشاہدہ: اگر فنکشن COROUTINE_SUSPENDED لوٹاتا ہے، تو موجودہ تھریڈ جاری ہو جاتا ہے۔ جب غیر ہم آہنگ آپریشن مکمل ہوتا ہے، Continuation.resumeWith کال کیا جاتا ہے اور اسٹیٹ مشین اگلے لیبل سے جاری رہتی ہے۔
suspend فنکشن کا اعلان عام فنکشن سے مختلف نہیں ہے، سوائے fun سے پہلے suspend کیورڈ کے۔ صرف ایک پابندی ہے: suspend فنکشن صرف coroutine یا کسی دوسرے suspend فنکشن سے کال کیا جا سکتا ہے۔
suspend fun delayAndReturn(ms: Long): String {
delay(ms)
return "Done after ${ms}ms"
}
اس مثال میں، delay بھی ایک suspend فنکشن ہے جو تھریڈ کو بلاک کیے بغیر مخصوص ملی سیکنڈز کے لیے coroutine کو روکتا ہے۔ تاخیر کے بعد، عملدرآمد دوبارہ شروع ہوتا ہے۔
fun main() = runBlocking {
val result = delayAndReturn(1000)
println(result)
}
runBlocking عام دنیا اور coroutines کے درمیان ایک پل بناتا ہے۔ lambda کے اندر، کسی بھی suspend فنکشن کو کال کیا جا سکتا ہے۔
Kotlin فنکشنل اقسام کے suspend ورژنز کو سپورٹ کرتا ہے — suspend () -> T اور suspend (A) -> B۔ یہ اعلیٰ ترتیب کے فنکشنز میں غیر ہم آہنگ lambdas منتقل کرنے کی اجازت دیتا ہے:
suspend fun withRetry (
retries: Int = 3,
block: suspend () -> T
): T {
repeat(retries - 1) {
try { return block() }
catch (_: Exception) { delay(100) }
}
return block()
}
withRetry فنکشن ایک suspend lambda لیتا ہے اور غلطیوں پر اس کے عملدرآمد کی دوبارہ کوشش کرتا ہے۔ یہ دوبارہ کوشش کے ساتھ نیٹ ورک کی درخواستوں کے لیے ایک عام نمونہ ہے۔
suspend اور عام فنکشنز کے درمیان فرق صرف ایک موڈیفائر شامل کرنے سے آگے بڑھتا ہے۔ آئیے اہم فرقوں کو دیکھتے ہیں۔
| خصوصیت | عام فنکشن | suspend فنکشن |
|---|---|---|
| عملدرآمد کا تھریڈ | مکمل ہونے تک تھریڈ کو بلاک کرتا ہے | تھریڈ جاری کر سکتا ہے اور بعد میں دوبارہ شروع کر سکتا ہے |
| کمپائلر پیرامیٹرز | صرف مخصوص کردہ پیرامیٹرز | آخر میں پوشیدہ Continuation |
| عام فنکشن سے کال | ہاں | نہیں |
| اسٹیک | طبعی تھریڈ اسٹیک | ہیپ میں اسٹیٹ مشین + پوائنٹس کے درمیان طبعی اسٹیک |
| واپسی کی قیمت | براہ راست قیمت | قیمت یا COROUTINE_SUSPENDED |
| کارکردگی | کم سے کم اضافی لاگت | ~چند نینو سیکنڈز فی اسٹیٹ مشین (Kotlin 1.9+) |
عام فنکشن میں Continuation نہیں ہوتا — اس کے پاس اسٹیٹ محفوظ کرنے کی جگہ نہیں اور عملدرآمد دوبارہ شروع کرنے کے لیے کچھ نہیں۔ اگر آپ کو عام فنکشن سے suspend فنکشن کال کرنے کی ضرورت ہے، تو runBlocking (ٹیسٹ کے لیے) یا CoroutineScope.launch (زندگی کے چکر سے آگاہی کے ساتھ پروڈکشن کے لیے) استعمال کریں۔
آئیے Kotlin کے ساتھ Android ایپس میں suspend فنکشن استعمال کرنے کے تین حقیقی منظرنامے دیکھتے ہیں۔
Room براہ راست suspend فنکشنز کو سپورٹ کرتا ہے — سوال خود بخود پس منظر کے تھریڈ میں عمل میں آتا ہے:
@Dao
interface UserDao {
@Query("SELECT * FROM users WHERE id = :id")
suspend fun getUser(id: Int): User?
@Insert
suspend fun insertUser(user: User)
}
Room اندرونی طور پر سوال کو عمل میں لانے کے لیے Dispatchers.IO استعمال کرتا ہے، اور نتیجہ اس ڈسپیچر پر واپس کیا جاتا ہے جہاں suspend فنکشن کال کیا گیا تھا۔
class ProfileViewModel : ViewModel() {
private val repo = ProfileRepository()
fun loadProfile(id: String) {
viewModelScope.launch {
val profile = repo.getProfile(id)
_profile.value = profile
}
}
}
ViewModelScope.launch ایک coroutine بناتا ہے، جس کے اندر getProfile suspend فنکشن کال کیا جاتا ہے۔ نتیجہ حاصل کرنے کے بعد، یوزر انٹرفیس مرکزی تھریڈ پر اپ ڈیٹ ہوتا ہے۔
suspend fun placeOrder(cart: Cart): OrderResult {
val validated = validateCart(cart)
val payment = processPayment(validated)
val receipt = sendReceipt(payment)
return receipt
}
تین suspend فنکشنز ترتیب وار عمل میں آتے ہیں۔ ہر مرحلے پر، coroutine تھریڈ کو بلاک کیے بغیر روک سکتا ہے۔ اگر کوئی مرحلہ استثنا پھینکتا ہے، تو بقیہ مراحل عمل میں نہیں آتے، جو غلط آرڈر کی حالتوں سے بچاتا ہے۔
تجربہ کار Kotlin ڈویلپر بھی suspend فنکشنز ڈیزائن کرتے وقت غلطیاں کرتے ہیں۔ آئیے سب سے عام غلطیاں دیکھتے ہیں۔
suspend فنکشن کوڈ کو خود بخود غیر ہم آہنگ نہیں بناتا۔ Thread.sleep()، InputStream.read() اور دیگر بلاک کرنے والی کالیں پھر بھی تھریڈ کو بلاک کریں گی۔ بلاک کرنے والی کارروائیوں کو لپیٹنے کے لیے withContext(Dispatchers.IO) استعمال کریں۔
اگر کوئی فنکشن دوسرے suspend فنکشنز کو کال نہیں کرتا اور غیر ہم آہنگ کارروائیاں نہیں کرتا — تو suspend موڈیفائر بے کار ہے۔ یہ اسٹیٹ مشین پر اضافی لاگت ڈالتا ہے اور کال کرنے کے سیاق و سباق کو محدود کرتا ہے۔ فنکشن کو صرف اس وقت suspend بنائیں جب وہ واقعی رکتا ہو۔
جب coroutine منسوخ ہوتا ہے، suspend فنکشنز CancellationException پھینکتے ہیں۔ اسے بغیر سوچے نہ پکڑیں — آپ کال کرنے والے کوڈ کو منسوخی کو صحیح طریقے سے مکمل کرنے کی صلاحیت سے محروم کر رہے ہیں۔ اگر آپ کو حتمی کارروائی کرنے کی ضرورت ہے، تو finally بلاک اور NonCancellable استعمال کریں۔
suspend fun safeOperation() {
try {
doWork()
} finally {
withContext(NonCancellable) {
cleanup()
}
}
}
finally بلاک ہمیشہ عمل میں آتا ہے، منسوخی پر بھی، اور NonCancellable یقینی بناتا ہے کہ صفائی میں خلل نہ پڑے۔
آپ coroutine بنائے بغیر براہ راست کال بیک سے suspend فنکشن کال نہیں کر سکتے۔ کال بیک اسٹائل کو coroutines کے مطابق ڈھالنے کے لیے suspendCoroutine یا suspendCancellableCoroutine استعمال کریں۔
اکثر پوچھے گئے سوالات
ہاں، تکنیکی طور پر suspend فنکشن دوسرے suspend فنکشنز کو کال نہیں کر سکتا۔ کمپائلر ایک اسٹیٹ (label 0) کے ساتھ اسٹیٹ مشین بنائے گا۔ تاہم، اس طرح کے فنکشن کا کوئی عملی فائدہ نہیں — یہ عام فنکشن کی طرح چلتا ہے لیکن اضافی لاگت کے ساتھ۔ بغیر ضرورت کے suspend استعمال نہ کریں۔
Kotlin kotlinx-coroutines-debug فراہم کرتا ہے — DebugProbes اور coroutine ٹریسنگ ٹولز کے ساتھ ایک لائبریری۔ Android Studio میں Arctic Fox سے، ڈیبگر میں ایک بلٹ ان Coroutines ٹیب ہے جو فعال coroutines، ان کی حالت اور معطلی پوائنٹس دکھاتا ہے۔
ہر معطلی پوائنٹ اسٹیٹ مشین میں ایک نیا اسٹیٹ بناتا ہے۔ زیادہ تر ایپلیکیشنز کے لیے، ایک پوائنٹ کی اضافی لاگت چند نینو سیکنڈز ہے (Kotlin 1.9+)۔ صرف لوپ میں دسیوں ہزار پوائنٹس کے ساتھ آپ کو آپریشنز کو یکجا کرنے یا sequence/flow استعمال کرنے پر غور کرنا چاہیے۔
Kotlin میں، suspend ایک فنکشن قسم کا موڈیفائر ہے، واپسی کی قیمت کا نشان نہیں (جیسے C# میں async)۔ کوئی بھی suspend فنکشن کسی بھی پیرامیٹر اور واپسی کی قسم رکھ سکتا ہے، اور اس کی کال نحوی طور پر عام فنکشن کال سے مختلف نہیں — کال کی جگہ پر کوئی await آپریٹر نہیں ہے۔
موافقت کے لیے suspendCancellableCoroutine استعمال کریں۔ اندر، آپ ایک کال بیک رجسٹر کرتے ہیں جو continuation.resume() کو کال کرتا ہے، اور اگر کال بیک سبسکرپشن منسوخی کو سپورٹ کرتا ہے تو منسوخی کا ٹوکن واپس کرتے ہیں۔ یہ پرانے Android API کو لپیٹنے کا معیاری نمونہ ہے۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں