[Flutter] Dart의 비동기 요청은 어떻게 Race Condition을 제어할까?

Raon·2024년 12월 7일
0

Flutter

목록 보기
26/26

나는 Isolate를 자주 애용해왔다. 그래서 스스로 Isolate에 대해 상당히 잘 알고 있다고 자부했었다.

하지만, 최근에 옆자리 동료 안드로이드 개발자(나는 안드로이드 팀에 소속된 플러터 개발자다)와의 대화 중, Isolate에 대한 이야기가 나왔는데, 동료 분께서 말하길,

동료 : "그러면 Dart는 비동기요청으로 10000번 반복문을 돌리면 어떻게 되나요?"
나 : "당연히 10000이 나오죠?"
동료 : "아닐텐데... 한번 해보셨나요?"
나 : "해봤죠 ㅋㅋㅋ 10000나와요 ㅋㅋㅋㅋ"
동료 : "한번 테스트 해보는거 어때요?"
나 : "오 재밌겠네요!"

대략 이런 느낌의 대화를 주고 받은 뒤, 바로 테스트를 해보기 위해 코드를 작성해봤다.

Kotlin

코틀린으로 비동기로 동작하는 간단한 함수를 만들었다.
cnt변수에 100번씩 더하는 Job을 100개 만드는 작업으로, 내가 예상한 결과는 당연히 10000이 출력되어야했다.

하지만 결과는 내 예상과는 달랐다.

출력된 결과는 9635로 내가 예상한 10000과는 값에 차이가 있었다.

이러한 이유가 왜 발생하는지 알아보기 전에, Dart코드로 실행한 결과를 한 번 보도록 하자.

Dart

Dart로 작성한 코드는 다음과 같다.

위 코드를 통해 출력된 결과는 예상대로 10000이 출력되었다.

Race Condition

이제 본격적인 주제인 "어째서 Kotlin과 Dart"의 결과가 다른지에 대해 알아보도록 하자.

사실, 이상하게 들리겠지만 Kotlin과 같이 10000이 출력되지 않는 것이 당연한 결과이다.

왜냐면, 우리가 작성한 예제는 "Race condition"을 고려하지 않았기 때문이다.
그러면 Race Condition이 무엇일까?

위의 이미지를 보면 Person A라는 이름의 쓰레드와 Person B 쓰레드의 읽고 쓰는 작업에 있어 이상한 점을 느낄 수 있을 것이다.

바로, 두 쓰레드가 동시에 같은 값을 읽는다는 점이다.

이렇게 "두 쓰레드가 동시에 메모리에 접근해 동일한 값을 읽어들이는 현상을 경합상태(Race condition)이라고 한다.

이는 메모리에 적재된 정보를 Thread가 읽어들일 때 발생하는 당연한 현상으로, 프로그래밍 언어에 국한되지 않는다.

이렇게만 보면 Race Condition으로 인해 굉장히 개발하는데 있어 좋지 않은 문제들을 초래할 것 같아 보이지만, 이를 해결하기 위해 Mutex와 같은 개념을 도입해 경합상태가 발생하지 않도록 한다.

그러면 Dart는 왜 이러한 문제가 발생하지 않는 것일까? 이에 대한 해답을 얻기 위해서는 Dart 공식 문서의 글을 조금 자세히 살펴볼 필요가 있다.

대부분의 현대 디바이스들은 멀티 코어 CPU를 가집니다. 이러한 많은 코어를 활용하기 위해, 개발자들은 종종 동시에 실행되는 공유 메모리 스레드를 사용합니다. 그러나, 공유 상태 동시성은 에러가 발생하기 쉽고 복잡한 코드로 이어질 수 있습니다.

Dart 코드는 스레드가 아닌 isolate의 내부에서 실행됩니다. 각 isolate는 자신의 메모리 힙을 가지고, 다른 isolate에서 자신의 상태에 접근할 수 없습니다. 공유하는 메모리가 없기 때문에, 뮤텍스, 락을 고려할 필요가 없습니다.

Dart의 Isolate의 경우, 경합상태를 방지하기 위해 메모리 영역을 아예 공유하지 않는다.

하지만, Future의 경우에는 어떨까? Future는 Isolate를 새롭게 만들지 않고 비동기 작업을 수행한다. 이로 인해 경합상태가 발생하지 않을 것 같지만, 어째서인지 경합상태가 발생하지 않는다.

이에 대한 해답은 Dart SDK의 코드를 보면 알 수 있다.

https://github.com/dart-lang/sdk/blob/main/runtime/vm/isolate.h

위의 코드는 상당히 길어 이해하는것에 다소 어려움이 있을 순 있으나, 천천히 읽다보면 Mutex와 MuteLocker라는 타입이 보일 것이다.

이를 통해 Future는 dart 내부적으로 비동기 작업을 수행할 때 Mutex를 활용한다는 것을 알 수 있었다.

요약

  • Dart는 Race Condition을 내부적으로 제어해준다. 일반적으로는 개발자가 관리해줄 필요가 없다.
profile
Flutter 개발자

0개의 댓글