코 틀린 코 루틴은“이전의 일”을 보장합니까?


10

코 틀린 코 루틴은 "전의 어쩌면"보증을 제공합니까?

예를 들어, mutableVar이 경우 다른 스레드에 대한 쓰기 및 후속 읽기 (잠재적으로) 간에 " 어쩌면 이전"이 보장됩니까 ?

suspend fun doSomething() {
    var mutableVar = 0
    withContext(Dispatchers.IO) {
        mutableVar = 1
    }
    System.out.println("value: $mutableVar")
}

편집하다:

어쩌면 추가 예제는 Kotlin이 더 많기 때문에 (변이성을 제외하고) 더 나은 질문을 분명히 할 것입니다. 이 코드는 스레드로부터 안전합니까?

suspend fun doSomething() {
    var data = withContext(Dispatchers.IO) {
        Data(1)
    }
    System.out.println("value: ${data.data}")
}

private data class Data(var data: Int)

JVM에서 실행될 때 Kotlin은 Java와 동일한 메모리 모델을 사용합니다.
Slaw

1
@ 슬로, 나는 그것을 알고있다. 그러나 후드 아래에는 많은 마술이 있습니다. 따라서 코 루틴에서 얻을 수있는 보장이 있는지 또는 모든 것이 있는지 여부를 이해하고 싶습니다.
Vasiliy

어쨌든 두 번째 예제는 훨씬 간단한 시나리오를 제시합니다.이 예제는에서 생성 된 객체를 사용하는 withContext반면 첫 번째 예제는 먼저 생성 withContext한 후를 변경 한 다음에 읽습니다 withContext. 따라서 첫 번째 예는 더 많은 스레드 안전 기능을 연습합니다.
Marko Topolnik

... 그리고 두 예제는 가장 사소한, 이전의 "프로그램 순서"측면을 보여줍니다. 나는 기본 JVM이 아닌 코 루틴 수준에 대해 이야기하고 있습니다. 따라서 기본적으로 Kotlin 코 루틴이 너무 심각하게 깨져서 프로그램 순서를 제공하지도 않는지 묻습니다.
Marko Topolnik

1
@MarkoTopolnik, 내가 틀렸다면 나를 수정하지만 JLS는 동일한 스레드에서 실행하기 위해 "프로그램 순서가 발생합니다"만 보장합니다. 이제 코 루틴을 사용하면 코드가 순차적으로 보이지만 실제로 다른 스레드로 코드를 오프로드하는 일부 기계가 있습니다. 귀하의 요점은 "이것은 내가 확인하는 데 시간을 낭비하지 않는 기본적인 보증"이라는 것을 이해하지만,이 질문에 대해 엄격한 답변을 구했습니다. 필자가 작성한 예제가 스레드 안전하다고 확신하지만 그 이유를 이해하고 싶습니다.
Vasiliy

답변:


6

작성한 코드에는 공유 상태에 대한 세 가지 액세스 권한이 있습니다.

var mutableVar = 0                        // access 1, init
withContext(Dispatchers.IO) {
    mutableVar = 1                        // access 2, write
}
System.out.println("value: $mutableVar")  // access 3, read

세 가지 액세스는 순차적으로 순서가 정해져 있으며 그 사이에 동시성이 없습니다. Kotlin의 인프라는 스레드 풀로 핸드 오프하고 호출 코 루틴으로 돌아갈 때 발생 하는 우위 를 설정하도록 보장합니다 IO.

다음은 아마도 더 설득력있는 예입니다.

launch(Dispatchers.Default) {
    var mutableVar = 0             // 1
    delay(1)
    mutableVar = 1                 // 2
    delay(1)
    println("value: $mutableVar")  // 3
}

일시 delay중단 가능한 함수 이므로 Default스레드 풀이 지원 하는 디스패처를 사용하므로 행 1, 2 및 3은 각각 다른 스레드에서 실행될 수 있습니다. 따라서 발생 전 보장 에 대한 질문은 이 예제에도 동일하게 적용됩니다. 반면 에이 경우이 코드의 동작이 순차적 실행 원칙과 일치한다는 것이 완전히 분명합니다.


1
감사. 실제로이 질문을하도록 동기를 부여한 것은 "안심"후의 부분입니다. 읽을 수있는 문서에 대한 링크가 있습니까? 또는 에지가 설정되기 전에 이러한 상황이 발생하는 소스 코드에 대한 링크도 큰 도움이 될 것입니다 (가입, 동기화 또는 기타 방법).
Vasiliy

1
이것은 내가 그것을 확인하는 데 시간을 낭비하지 않을 것이라는 기본적인 보증입니다. 후드 아래에서 끓어 오르고 executorService.submit()작업 완료를 기다리는 전형적인 메커니즘이 있습니다 (a CompletableFuture또는 유사한 것을 완료 ). 코 틀린 코 루틴의 관점에서 보면 여기에는 전혀 동시성이 없습니다.
Marko Topolnik

1
"스레드를 일시 중단하고 다른 코어에서 재개 할 때 OS가 발생하기 전에 OS를 보장합니까?"와 비슷한 질문으로 생각할 수 있습니다. 스레드는 CPU 코어가 스레드에 어떤 것인지 코 루틴해야합니다.
Marko Topolnik

1
설명해 주셔서 감사합니다. 그러나 나는 왜 이것이 작동하는지 이해하기 위해이 질문을했다. 나는 당신의 요점을 알지만, 지금까지는 내가 찾고있는 엄격한 대답이 아닙니다.
Vasiliy

2
글쎄 ... 실제로이 스레드가 코드가 순차적이라는 것을 설정하지 않았다고 생각합니다. 확실히 그것을 주장했다. 나도 성능에 영향을 미치지 않고 예제가 예상대로 작동하도록 보장하는 메커니즘을 보는 데 관심이 있습니다.
G. Blake Meike

3

Kotlin의 코 루틴은 보증 전에 제공됩니다.

규칙은 다음과 같습니다 코 루틴 내부 코드 이전에 a가 함수 호출 일시 중단 하기 전에 발생 코드 (가) 전화를 일시 중지합니다.

코 루틴은 마치 일반 스레드 인 것처럼 생각해야합니다.

Kotlin의 코 루틴은 여러 스레드에서 실행될 수 있지만 변경 가능한 상태의 관점에서 스레드와 같습니다. 동일한 코 루틴에서 두 작업을 동시에 수행 할 수 없습니다.

출처 : https://proandroiddev.com/what-is-concurrent-access-to-mutable-state-f386e5cb8292

코드 예제로 돌아 가기 람다 함수 본문에서 vars를 캡처하는 것은 특히 람다가 코 루틴 일 때 가장 좋은 아이디어는 아닙니다. 람다 앞의 코드는 코드 내부에서 발생하지 않습니다.

참조 https://youtrack.jetbrains.com/issue/KT-15514를


실제로 규칙은 다음과 같습니다. 일시 중단 함수 호출 이전 의 코드는 일시 중단 함수 내부 의 코드 이전 에, 일시 중단 호출 후 코드 이전에 발생 합니다. 이것은 차례로 "코드의 프로그램 순서는 또한 코드의 사전에 발생 하는 순서"로 일반화 될 수 있습니다 . 해당 명령문에 일시 중단 가능한 기능에 특정한 항목이 없음에 유의하십시오.
Marko Topolnik
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.