Kotlin / เนทีฟมัลติเธรดโดยใช้โครูทีน
ฉันเคยถ่ายทำที่ kotlin หลายแพลตฟอร์มและมันยอดเยี่ยม แต่การทำเกลียวทำให้ฉันสะดุด การแช่แข็งของสถานะระหว่างเธรดมีความหมายในเชิงแนวคิดและใช้ได้ดีในตัวอย่างง่ายๆที่วัตถุขนาดเล็กหรือวัตถุดั้งเดิมถูกส่งผ่านไปมา แต่ในแอปพลิเคชันในโลกแห่งความเป็นจริงฉันไม่สามารถเข้าถึง InvalidMutabilityException ได้
ใช้ข้อมูลโค้ดทั่วไปต่อไปนี้จากแอป Android
class MainViewModel(
private val objectWhichContainsNetworking: ObjectWhichContainsNetworking
)
private var coreroutineSupervisor = SupervisorJob()
private var coroutineScope: CoroutineScope = CoroutineScope(Dispatchers.Main + coreroutineSupervisor)
private fun loadResults() {
// Here: Show loading
coroutineScope.launch {
try {
val result = withContext(Dispatchers.Default) { objectWhichContainsNetworking.fetchData() }
// Here: Hide loading and show results
} catch (e: Exception) {
// Here: Hide loading and show error
}
}
}
ไม่มีอะไรซับซ้อนมาก แต่ถ้าใช้ในโค้ดทั่วไปและเรียกใช้จาก Kotlin / Native แล้ว InvalidMutabilityException บน MainViewModel
ดูเหมือนว่าเหตุผลนี้คืออะไรก็ตามที่ส่งผ่านด้วยContextจะถูกแช่แข็งซ้ำดังนั้นเนื่องจาก objectWhichContainsNetworking เป็นคุณสมบัติของ MainViewModel และใช้ร่วมกับContextจากนั้น MainViewModel จะถูกตรึง
คำถามของฉันคือนี่เป็นเพียงข้อ จำกัด ของโมเดลหน่วยความจำ Kotlin / Native ปัจจุบันหรือไม่? หรืออาจจะเป็น Coroutines รุ่นปัจจุบัน? และมีวิธีใดบ้างในรอบนี้?
หมายเหตุ: Coroutines เวอร์ชัน: 1.3.9-native-mt. kotlin เวอร์ชัน 1.4.0
แก้ไข 1: ดูเหมือนว่าโค้ดลดขนาดลงด้านบนใช้งานได้จริง ปรากฎว่ารหัสปรักปรำเป็นตัวแปรที่อัปเดตได้ในโมเดลมุมมอง (ใช้เพื่ออ้างอิงถึงสถานะมุมมองสุดท้าย) ซึ่งจะหยุดนิ่งจากนั้นจะโยนข้อยกเว้นเมื่อพยายามที่จะกลายพันธุ์ ฉันจะพยายามใช้ Flow / Channels เพื่อให้แน่ใจว่าไม่จำเป็นต้องมีการอ้างอิง var และดูว่าวิธีนี้ช่วยแก้ปัญหาโดยรวมได้หรือไม่
หมายเหตุ: หากมีวิธีหลีกเลี่ยงไม่ให้ MainViewModel ถูกแช่แข็งตั้งแต่แรกก็ยังคงยอดเยี่ยม!
แก้ไข 2: แทนที่ var ด้วย Flow ฉันไม่สามารถรับการรวบรวมขั้นตอนมาตรฐานใน iOS ได้จนกว่าจะใช้ตัวช่วยที่นี่:https://github.com/JetBrains/kotlinconf-app/blob/master/common/src/mobileMain/kotlin/org/jetbrains/kotlinconf/FlowUtils.kt.
MainViewModel ยังคงหยุดนิ่ง แต่เนื่องจากสถานะทั้งหมดไม่เปลี่ยนรูปจึงไม่ใช่ปัญหาอีกต่อไป หวังว่าจะช่วยใครสักคน!
คำตอบ
ในโค้ดดั้งเดิมของคุณคุณกำลังอ้างถึงฟิลด์ของอ็อบเจ็กต์พาเรนต์ซึ่งทำให้คุณจับภาพพาเรนต์ทั้งหมดและหยุดการทำงาน ไม่ใช่ปัญหาเกี่ยวกับโครูทีน Coroutines เป็นไปตามกฎเดียวกันกับไลบรารีการทำงานพร้อมกันอื่น ๆ ทั้งหมดใน Kotlin / Native มันค้างแลมด้าเมื่อคุณข้ามเธรด
class MainViewModel(
private val objectWhichContainsNetworking: ObjectWhichContainsNetworking
)
//yada yada
private fun loadResults() {
coroutineScope.launch {
try {
val result = withContext(Dispatchers.Default) {
//The reference to objectWhichContainsNetworking is a field ref and captures the whole view model
objectWhichContainsNetworking.fetchData()
}
} catch (e: Exception) {}
}
}
เพื่อป้องกันไม่ให้สิ่งนี้เกิดขึ้น:
class MainViewModel(
private val objectWhichContainsNetworking: ObjectWhichContainsNetworking
){
init{
ensureNeverFrozen()
}
//Etc
สิ่งที่ซับซ้อนที่สุดกับโมเดลหน่วยความจำคือสิ่งนี้ ทำความคุ้นเคยกับสิ่งที่ถูกจับและหลีกเลี่ยง มันไม่ใช่เรื่องยากเมื่อคุณคุ้นเคย แต่คุณต้องเรียนรู้พื้นฐาน
ฉันได้พูดถึงเรื่องนี้แล้ว:
Kotlin ในทางปฏิบัติ / ภาวะพร้อมกันของพื้นเมือง
Kotlin Native Concurrency Hands On
KotlinConf KN Concurrency
โมเดลหน่วยความจำกำลังเปลี่ยนไป แต่คงต้องใช้เวลาสักพักก่อนที่จะถึงที่หมาย เมื่อคุณคุ้นเคยกับโมเดลหน่วยความจำแล้วปัญหาที่ไม่เปลี่ยนรูปมักจะวินิจฉัยได้ง่าย