flowOn وbuffer: السياق والضغط العكسي
غيّر سياق الانبعاث باستخدام flowOn وخزّن الانبعاثات مؤقتًا للتعامل مع الضغط العكسي.
flowOn وbuffer: السياق والضغط العكسي درس مجاني في Kotlin Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Kotlin Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Kotlin Academy 4 دروس في المجموع.
سياق Flow
يعمل التدفق افتراضيًا في سياق coroutine التي تستدعي collect. ويكون الموزّع المستخدم من المنتج والمستهلك متطابقًا ما لم تغيّره.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
flow {
println("emit on: ${Thread.currentThread().name}")
emit(1)
}.collect {
println("collect on: ${Thread.currentThread().name}")
}
}flowOn يغيّر سياق المنبع
يشغّل flowOn(dispatcher) تدفق المنبع، أي كل ما يقع فوقه في السلسلة، باستخدام الموزّع المحدد، بينما يبقى التجميع على موزّع المستدعي.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
flow {
println("emit: ${Thread.currentThread().name}")
emit(1)
}.map {
println("map: ${Thread.currentThread().name}")
it * 2
}.flowOn(Dispatchers.Default) // above runs on Default
.collect {
println("collect: ${Thread.currentThread().name}")
}
}استخدام flowOn عدة مرات في سلسلة
يمكنك استخدام flowOn عدة مرات. يؤثر كل استخدام في المعاملات الواقعة فوقه مباشرة، وصولًا إلى flowOn السابق.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
flow { emit(1) }
.map { it + 1 }.flowOn(Dispatchers.IO) // map runs on IO
.map { it * 2 }.flowOn(Dispatchers.Default) // this map runs on Default
.collect { println("Result: $it") } // collect on Main (runBlocking)
}مشكلة الضغط العكسي
عندما يصدر المنتج القيم بسرعة تفوق قدرة المستهلك على معالجتها، تتراكم القيم في قائمة انتظار. ومن دون التخزين المؤقت، يضطر المنتج إلى الانتظار.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val time = System.currentTimeMillis()
flow {
repeat(3) { i ->
delay(100) // fast producer
emit(i)
}
}.collect {
delay(300) // slow consumer
println("Got $it in ${System.currentTimeMillis() - time}ms")
}
}المعامل buffer()
يشغّل buffer() المنتج والمستهلك بشكل متزامن في coroutine منفصلتين، ويخزّن القيم الصادرة مؤقتًا في قناة. لذلك لا ينتظر المنتج المستهلك.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val time = System.currentTimeMillis()
flow {
repeat(3) { i -> delay(100); emit(i) }
}.buffer() // producer and consumer run concurrently
.collect {
delay(300)
println("Got $it in ${System.currentTimeMillis() - time}ms")
}
}سعة buffer
تحدد buffer(capacity) حجم مخزن القناة المؤقت. وعندما يمتلئ المخزن، يتوقف المنتج مؤقتًا، وهذا هو الضغط العكسي. السعة الافتراضية هي 64.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.channels.Channel
fun main() = runBlocking {
flow { repeat(5) { emit(it) } }
.buffer(Channel.RENDEZVOUS) // 0: producer waits
// .buffer(Channel.BUFFERED) // default: 64
// .buffer(Channel.UNLIMITED) // unbounded
.collect { delay(50); println(it) }
}conflate() لأحدث قيمة فقط
يتخلص conflate() من القيم الوسيطة عندما يكون المستهلك بطيئًا، ويحتفظ بأحدث قيمة منبعثة فقط. وهذا مفيد لحالة واجهة المستخدم.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
flow {
repeat(5) { i -> emit(i); delay(50) }
}.conflate()
.collect { i ->
delay(150)
println("Collected: $i") // skips some values
}
}collectLatest للمستهلكين البطيئين
يلغي collectLatest كتلة التجميع الحالية عند وصول قيمة جديدة، ثم يعيد تشغيلها باستخدام أحدث قيمة.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
flow {
emit(1); delay(50)
emit(2); delay(50)
emit(3)
}.collectLatest { value ->
println("Processing $value")
delay(100) // gets cancelled if new value arrives
println("Done $value") // only prints for last value
}
}نمط flowOn + buffer
ادمج flowOn مع buffer: شغّل المنتج على IO، للشبكة أو القرص، وخزّن النتائج مؤقتًا، ثم اجمعها على Main.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun fetchItems(): Flow<String> = flow {
repeat(3) { i ->
delay(100) // simulate IO
emit("item-$i")
}
}.flowOn(Dispatchers.IO).buffer(10)
fun main() = runBlocking {
fetchItems().collect { println("UI: $it") }
}channelFlow للمنتجين المتزامنين
ينشئ channelFlow تدفقًا مدعومًا بقناة، مما يسمح لعدة coroutine بإصدار القيم بشكل متزامن من داخل الباني.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun concurrentFlow(): Flow<Int> = channelFlow {
launch { send(1) }
launch { send(2) }
launch { send(3) }
}
fun main() = runBlocking {
concurrentFlow().collect { println(it) }
}اختيار الاستراتيجية المناسبة
الخلاصة: استخدم flowOn لتبديل السياق، وbuffer لزيادة معدل المعالجة، وconflate للاحتفاظ بأحدث قيمة فقط في واجهة المستخدم، وcollectLatest لإلغاء المعالجة القديمة.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
// Guidelines:
// CPU-heavy production -> flowOn(Dispatchers.Default)
// IO-heavy production -> flowOn(Dispatchers.IO)
// Slow consumer -> buffer()
// UI state updates -> conflate() or StateFlow
// Search/autocomplete -> collectLatest or flatMapLatest
fun main() = runBlocking { println("Choose the right strategy!") }تحقق سريع
ما الذي يؤثر فيه flowOn داخل سلسلة التدفق؟
مراجعة
ينقل flowOn العمل الواقع في المنبع إلى موزّع آخر. ويفصل buffer بين المنتج والمستهلك لزيادة معدل المعالجة. ويتخلص conflate من القيم الوسيطة. ويلغي collectLatest المعالجة البطيئة عند وصول قيم جديدة.
تعلم Kotlin مع معلم ذكاء اصطناعي — مجانًا
اكتب وقم بتشغيل أكوادك الفعلية في المتصفح، واحصل على مساعدة فورية من معلم ذكاء اصطناعي متاح 24/7، واستمر من حيث توقفت على الويب أو في التطبيق.
- الدورات
- 51
- الدروس
- 203
الأسئلة الشائعة
هل درس «flowOn وbuffer: السياق والضغط العكسي» مجاني؟
نعم — نص درس «flowOn وbuffer: السياق والضغط العكسي» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Kotlin Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Kotlin Academy 4 دروس في المجموع.
ماذا ستتعلم في «flowOn وbuffer: السياق والضغط العكسي»؟
غيّر سياق الانبعاث باستخدام flowOn وخزّن الانبعاثات مؤقتًا للتعامل مع الضغط العكسي. تتمرن على Kotlin Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Kotlin Academy؟
لا تُشترط خبرة سابقة. Kotlin Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.
كم من الوقت يستغرق درس «flowOn وbuffer: السياق والضغط العكسي»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Kotlin Academy هذا؟
نعم. كل درس في Kotlin Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- معاملات Flow: map وfilter وtransform وtake
- catch وonCompletion: معالجة الأخطاء في Flow
- combine وzip: دمج تدفقات Flow متعددة
- flowOn وbuffer: السياق والضغط العكسي