[Dart]동시성과 Isolate

한상욱·2024년 8월 22일
0

Dart

목록 보기
2/3
post-thumbnail

들어가며

오늘날의 대부분의 디바이스는 멀티 코어 CPU를 가지고 있습니다. 그렇기에 개발자들은 효율적으로 멀티 코어 CPU를 이용하기 위하여 공유 메모리 스레드를 이용합니다. 이러한 것은 동시성과 연결되게 됩니다. 공유 메모리를 이용하기에 에러가 발생할 수 있고, 에러를 방지하기 위해 복잡하게 코드가 작성됩니다.

Dart도 동시성을 지원합니다. 이 글에서는 Dart는 어떻게 동시성을 제어하는지에 대해서 알아보겠습니다.

Dart는 어떻게 동작할까?

Dart코드는 쓰레드가 아니라 main isolate의 내부에서 실행됩니다. isolate는 개별적인 메모리 힙을 갖고 있으며, 다른 isolate는 접근할 수 없습니다. 이는 곧, 공유 메모리가 존재하지 않는 것을 의미하며 뮤텍스, 락을 고려할 필요가 없다는 의미입니다.

isolate를 이용하면 Dart언어가 사용가능한 추가 프로세스 코어를 사용하여 여러가지 독립적인 코드를 동시에 수행할 수 있습니다.

isolate?

isolate는 어떻게 보면 쓰레드, 프로세스와 비슷합니다. 하지만, 고유 메모리와 이벤트 루프를 작동시키는 단일 쓰레드를 갖고 있는 독립적인 프로세스입니다.

isolate 생명 주기

isolate는 Dart코드가 실행되면서 시작됩니다. Dart코드에는 사용자 입력 처리 예를 들어, 버튼 탭이라던지 혹은 파일 입출력, Http 통신 등 이벤트 리스너를 등록하게 됩니다. 그리고 등록된 모든 것들이 처리된 후 isolate는 종료되는 것이죠.

등록된 Event는 Event Queue에 순서대로 들어가며, FIFO의 형태로 해당 Event들을 처리하게 됩니다. 물론, Dart코드가 종료되더라도 Event를 처리하지 못했다면, isolate는 계속 유지되고 모두 처리한 후 종료됩니다.

백그라운드 워커

만약 Event Queue에 등록된 Event 중 수행시간이 긴 Event를 처리한다면 어떨까요?

위 그림에서는 Tap Event가 굉장히 긴 시간을 소요합니다. 이로 인해서 다음 Repaint Event 처리까지 오랜 시간이 걸리며, 앱은 멈춰있는 시간이 길어지고 최악의 경우 UI가 버벅거리다가 반응하지 않게 됩니다.

그렇기에 오랜 시간을 소요하는 Event는 다른 isolate로 넘겨서 연산을 수행할 수 있으며 이러한 isolate는 백그라운드 워커라고 합니다.

isolate는 메시지를 통해서 객체를 주고받을 수 있습니다. 이를 이용해서 오랜 시간이 소요되는 Event를 백그라운드 워커에 넘겨주고 연산 결과를 main isolate에서 전달받는 것이죠.

다만, 모든 객체가 메세지로 전달될 수 있는 것은 아닙니다. 예를 들어, 배열을 주고받는 다면 배열의 모든 객체가 전달될 수 있어야 하며, 전달되지 못하는 객체가 있다면 전송에 실패합니다.

다수의 워커 생성 예시

Dart코드에서 Isolate를 이용하여 여러 워커를 생성해봅시다. 이 워커들은 각 연산을 동시에 수행하게 되며 독립적이므로 서로 영향을 끼칠 수 없습니다.

Isolate.run() 코드를 이용하면 간단하게 isolate를 생성할 수 있습니다.

import 'dart:isolate';

void main() {
  Isolate.run(process1);
  Isolate.run(process2);
  Isolate.run(process3);
}

Future<void> process1() async {
  for (var i = 0; i < 3; i++) {
    await Future.delayed(Duration(seconds: 1));
    print("1번 isolate");
  }
}

Future<void> process2() async {
  for (var i = 0; i < 3; i++) {
    await Future.delayed(Duration(seconds: 1));
    print("2번 isolate");
  }
}

Future<void> process3() async {
  for (var i = 0; i < 3; i++) {
    await Future.delayed(Duration(seconds: 1));
    print("3번 isolate");
  }
}

위 코드에서는 단순하게 각 isolate에서 문자열을 출력하는 형식입니다. 동시에 연산을 수행하기 때문에 각 연산은 아래와 같은 결과로 출력됩니다.

이렇게 번호가 랜덤하게 등장하는 것은 터미널에서 출력하는 것은 하나로 제한되어 있기에 실제로는 동시에 수행하지만, 한줄씩 출력되기 때문입니다.

이렇게, 간단하게 isolate의 개념과 다루는 방법에 대해서 알아보았습니다.

이미지 출처 : https://dart-ko.dev/language/concurrency#isolate-%EC%9E%91%EB%8F%99-%EB%B0%A9%EC%8B%9D

profile
자기주도적, 지속 성장하는 모바일앱 개발자가 되기 위해

0개의 댓글