본문 바로가기

Flutter

Dart : isolate

일반적인 프로그래밍 언어는 순차적으로 코드 실행한다. 그렇게 코드를 실행 중에 처리시간이 긴 작업(특히 UI와 관련된 상황 or 서버통신)을 만나면 프로그램이 기다리는 것처럼 느낄 수도 있다. 이러한 상황을 해결하기 위해, 요청한 작업의 결과를 기다리지 않고 바로 다음 작업으로 넘어감(비동기)으로써 프로그램의 실행을 기다리지 않게끔 한다.

 

이러한 문제 해결 방식을 비동기 프로그래밍(Asynchronous programming)이라고 한다.

⇒ 보통 Sub Thread(서브 쓰레드)를 생성해서 작업을 할당하는 것을 비동기 프로그래밍 이라고 한다.

 

안드로이드 Kotlin 개발에서는 Coroutine 을 통해 비동기 프로그래밍 하기를 구글 Jetpack에서 적극 권장하고, FlutterFuture, Stream 을 통해서 비동기 프로그래밍을 지원한다.

 

Flutter는 Dart 언어를 사용하며, Flutter의 비동기 프로그래밍을 이해가기 위해서는 Dart의 isolate라는 다트의 독특한 구조부터 알아야 한다.

 

 

먼저 아래의 공식 영상을 꼭 보고 다음을 보길 바란다.

Isolates and Event Loops - Flutter in Focus

https://www.youtube.com/watch?v=vl_AaCgudcY

 


 

isolate

isolate라는 단어는 격리하다는 의미이며, Dart의 isolate도 그 의미와 연관이 깊다.

Dart의 isolate는 작성된 코드가 실행되는 공간이며, 싱글스레드(이벤트 루프)를 통해 작업을 처리한다.

Flutter 에서 가장 기본이 되는 isolate는 main isolate 이며, 런타임에 생성된다.

 

Flutter 코드는 main isolate 에서 시작하여 코드가 진행이 되는데, main isolate 에서 모든 코드를 작업하는 것은 main isolate 에게 너무 많은 부하를 주는 것이며, 앱성능 저하를 일으키는 주 원인이다. 이때 작업을 분산시키기 위하여 추가로 isolate를 생성할 수 있다.

이 행위는 다른 언어에서는 '쓰레드를 생성한다' 라는 의미와 비슷한데, Flutter 에서는 'isolate를 생성한다'고 한다. 다만 기존의 언어에서 사용하는 쓰레드와 차이점이 있다.

 

isolate 구조 및 기존 스레드와 차이점

Java 등의 다른 언어에서 사용하는 스레드는 다음과 같이 스레드가 서로 메모리를 공유하는 구조이다.

 

Java 쓰레드 구조

 

하지만 isolate의 스레드는 자체적으로 메모리를 가지고 있다. 따라서 새로운 isolate를 생성하면 해당 isolate에 별도의 고유한 메모리를 가진 스레드가 하나 더 생기는 것이다. 즉 메모리 공유가 되지 않는다.

 

서로 메모리를 공유하지 않기 때문에, 두 isolate가 함께 작업(데이터 공유)하려면 message를 주고받아야만 가능하다.

이것이 불편하다고 생각할 수도 있다. 하지만 멀티스레드 사용 시 늘 주의해야 하는 공유자원에 대한 컨트롤에 신경 쓰지 않아도 된다.

 

isolate에 포함되어 있는 이벤트 루프는 이벤트 큐에 쌓여있는 작업들을 오래된 순(FIFO)으로 하나씩 가져와서 처리하도록 하는 역할을 한다.

 


 

새로운 isolate 생성하기

새로운 isolate는 spawn을 통해서 만들 수 있다. 다음 예제를 보자.

 

main() 함수에서 isolate를 3개 spawn 하였다. 따라서 3개의 isolate가 만들어질꺼다. 그런데 실행결과를 보면 이상하다. 출력이 2개밖에 없다. (isolate 생성 순서와 출력 순서가 다른 것은 thread 경쟁에 의해 순서가 보장되지 않기 때문이다.)

위 예제를 여러 번 실행하다 보면 출력이 랜덤하게 1개, 2개, 3개가 된다.

 

 

isolate 간 message 주고받기

앞선 예제에서 Line 4에 주석 처리된 부분이 있다. 해당 부분의 주석(ReceivePort 객체)을 풀면 출력문이 기대했던 3개로 나온다.(???)

 

ReceivePort는 isolate 간에 message를 주고받을 수 있는 역할을 한다. ReceivePort는 sendPort라는 getter를 통해서 SendPort를 리턴 받는다. 따라서 message를 보내고(send) 받기(receive)가 가능하다.

 

message를 보낼 때는 SendPort의 send를 이용하고 수신할 때는 ReceivePort의 listen을 이용한다.

다음 예제는 main isolate가 5개의 isolate와 message를 주고받는 예제이다.

 

  • Line 6 : main isolate에서 사용할 ReceivePort인 mainReceiverPort를 생성한다.
  • Line 8~14 : mainReceiverPort에서 message를 수신하는 listen를 선언한다. 만약 수신한 message가 SendPort 타입이면 해당 SendPort로 count 변수를 message로 하여 send 한다. 수신한 message가 SendPort 타입이 아니면 message를 출력한다.
  • Line 17 : 5개의 isolate를 생성한다.
  • Line 22 : 새로 생성된 isolate의 RecivePort인 fooReceivePort를 생성한다.
  • Line 23 : isolate 생성 시 전달받은 main isolate의 SendPort를 이용하여 main isolate에 새로 생성된 isolate의 SendPort를 전달.
  • Line25~27 : main isolate에서 받은 message(count 변숫값)을 'received: &msg' 형태의 String으로 만들어 다시 main isolate로 보낸다. 이 String이 Line 12의 print()를 통해서 출력되는 것이다.

 

 

 

위의 isolate 구조

 


 

결론

  • Flutter는 isolate를 사용하여 쓰레드를 사용한다.
  • isolate는 메모리를 공유하지 않는다.
  • isolate를 이용하여 멀티쓰레드를 지원하는 것 처럼 보이게 만든다. ⇒ 싱글스레드[이벤트루프] 가 여러개 존재한다.
  • isolate는 저런 작업을 Dart VM에 구현이 되어 있고, 개발할때는 신경쓸 필요가 없을뿐. 일부러 공유를 못하게 한 것이다.

"Dart VM 에다가 쓰레드 더주세요" 하면 isolate에 포장해서 주는 시스템으로 생각하면 된다.

 

기존의 멀티스레드 프로그래밍은 메모리를 공유하고 있기 때문에 항상 Race Condition(경쟁 조건) 에 대해 대응하는 코드(세마포어,뮤텍스 등등)를 작성해야 하기에 굉장히 난이도가 높다.

 

하지만 날이 갈수록 고성장하는 하드웨어 스펙(CPU성능, 메모리 적재능력과 속도)을 보면서, Dart는 개발자가 굳이 멀티스레드 프로그래밍을 하는것 보다, 하드웨어 점유가 조금 높아진다 하더라도 편하게 개발할 수 있게 기능을 제공하자 라는 쪽으로 방향성이 생긴것으로 보인다.(개인적인 생각)

 

그런데 Dart VM을 지원하는 모바일 OS 에서는 isolate를 사용할 수 있지만, Web에서는 Dart VM을 지원하지 않기 때문에 isolate를 사용이 불가능하다.

 

추가적인 정보는 아래에서 확인할 것.

 


How isolates work

https://dart.dev/guides/language/concurrency#how-isolates-work

 

Concurrency in Dart

Use isolates to enable parallel code execution on multiple processor cores.

dart.dev

The Engine architecture

https://github.com/flutter/flutter/wiki/The-Engine-architecture#threading

 

GitHub - flutter/flutter: Flutter makes it easy and fast to build beautiful apps for mobile and beyond

Flutter makes it easy and fast to build beautiful apps for mobile and beyond - GitHub - flutter/flutter: Flutter makes it easy and fast to build beautiful apps for mobile and beyond

github.com

 

'Flutter' 카테고리의 다른 글

[GoRouter] Go vs Push  (0) 2024.02.14
싱글턴 패턴 Singleton Pattern  (0) 2024.02.09
Unit Test  (0) 2022.12.01
gskinner  (0) 2022.11.22
플러터에서 자주 쓰이는 Dart 언어 특징들  (0) 2022.11.21