코 루틴을 사용한 Kotlin / 네이티브 멀티 스레딩

Aug 19 2020

나는 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에서 실행하는 경우 MainViewModel에 InvalidMutabilityException을 발생시킵니다.

그 이유는 withContext에 전달 된 모든 것이 재귀 적으로 고정되어 있으므로 objectWhichContainsNetworking이 MainViewModel의 속성이고 withContext에서 사용되기 때문에 MainViewModel이 고정에 걸리기 때문인 것 같습니다.

제 질문은 이것이 현재 Kotlin / Native 메모리 모델의 한계 일 뿐입니 까? 아니면 현재 버전의 코 루틴일까요? 그리고 이것에 대해 어떤 방법이 있습니까?

참고 : 코 루틴 버전 : 1.3.9-native-mt. kotlin 버전 1.4.0.


편집 1 : 그래서 위의 슬림 다운 코드가 실제로 잘 작동하는 것 같습니다. 유죄 코드는 뷰 모델 (마지막 뷰 상태에 대한 참조를 유지하는 데 사용됨)에서 업데이트 가능한 변수였으며, 고정 된 다음 변경하려고 할 때 예외를 throw합니다. 흐름 / 채널을 사용하여 var 참조가 필요하지 않은지 확인하고 이것이 전체 문제를 해결하는지 확인하려고합니다.

참고 : 처음에 MainViewModel이 동결되는 것을 방지하는 방법이 있다면 여전히 환상적 일 것입니다!


편집 2 : var를 Flow로 대체했습니다. 여기 헬퍼를 사용할 때까지 iOS에서 표준 흐름 수집을 얻을 수 없습니다.https://github.com/JetBrains/kotlinconf-app/blob/master/common/src/mobileMain/kotlin/org/jetbrains/kotlinconf/FlowUtils.kt.

MainViewModel은 여전히 ​​고정되지만 모든 상태가 변경 불가능하므로 더 이상 문제가되지 않습니다. 누군가에게 도움이되기를 바랍니다!

답변

4 KevinGalligan Aug 19 2020 at 21:14

원래 코드에서 부모 개체의 필드를 참조하므로 전체 부모를 캡처하고 고정하게됩니다. 코 루틴의 문제가 아닙니다. 코 루틴은 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 네이티브 동시성 실습

KotlinConf KN 동시성

기억 모델은 변하고 있지만, 그것이 도착하기까지는 꽤 오래 걸릴 것입니다. 메모리 모델에 익숙해지면 일반적으로 변경 불가능한 문제를 진단하기가 쉽습니다.