Dart는 JavaScript와 같이 싱글스레드 언어이다(애초에 js잡겠다고 나온 언어이니..)
이러한 싱글 스레드 언어의 경우 이벤트 루프의 개념을 알고 넘어가는 게 중요하기에 간단히 정리해 보았다.
이벤트 루프는 이벤트나 작업을 관리하고 하나의 작업이 완료되면 다음 작업을 실행하는 역할을 하는 프로그래밍 구조이다. 이벤트 루프는 큐(queue)를 사용하여 이벤트나 작업을 관리하며 그 중 하나를 선택하여 실행한다.
Dart에서 이벤트 루프는 두 가지 주요 큐를 관리하는데 그것이 마이크로태스크 큐(Microtask Queue)와 이벤트 큐(Event Queue)이다.
1. 마이크로태스크 큐(Microtask Queue)
마이크로태스크 큐에 들어있는 작업들은 현재 실행 중인 코드가 끝나자마자 실행된다. 마이크로태스크는 우선 순위가 높아서 마이크로태스크 큐가 비워질 때까지 이벤트 루프는 이벤트 큐의 작업을 실행하지 않는다. 마이크로태스크 큐는 비동기 작업의 완료를 알리거나 비동기 작업이 완료된 후에 수행할 추가 작업을 관리하는 데 주로 사용된다.
//microtask 예시
await fetchPost().then((_) => print("microtask 작업"));
2. 이벤트 큐(Event Queue)
이벤트 큐는 마이크로태스크 큐가 비어 있을 때에만 이벤트 루프에 의해 처리된다. 이벤트 큐에는 I/O, 타이머, 제스처, 키보드 이벤트, 그래픽 렌더링 등의 이벤트가 포함된다.
이런 방식으로 이벤트 루프는 동기적으로 실행되는 코드와 비동기적으로 실행되는 코드 사이에 조율을 하게 된다.
Dart에서는 Isolate
를 추가 생성해 별도의 스레드에서 코드를 실행할 수 있다. 각각의 Isolate
는 독립적인 메모리 공간과 하나의 Event Loop를 가지며 서로간에 메모리를 공유하지 않는다. 이로 인해 병렬 처리가 가능하게 되고 다중 CPU 코어를 활용할 수 있게 된다. 다음 코드를 살펴보자
import 'dart:isolate';
void main() async {
var mainIsolateReceivePort = ReceivePort(); // 메시지를 받기 위한 포트를 생성
Isolate.spawn(echoIsolate, mainIsolateReceivePort.sendPort); // 새 Isolate를 생성
// 새 Isolate로부터 SendPort를 받아옴
var echoIsolateSendPort = await mainIsolateReceivePort.first;
// 메시지 응답을 받을 ReceivePort
var response = ReceivePort();
// 새 Isolate에 메시지를 보냄
echoIsolateSendPort.send(['Hello', response.sendPort]);
// 새 Isolate로부터 응답을 받음
print(await response.first);
}
// 새 Isolate에서 실행되는 함수
void echoIsolate(SendPort mainIsolateSendPort) {
var receivePort = ReceivePort();
// Main Isolate에게 이 Isolate의 SendPort를 보냄
mainIsolateSendPort.send(receivePort.sendPort);
// 메시지를 받고 처리
receivePort.listen((message) {
var data = message[0];
SendPort replyTo = message[1];
replyTo.send('Echo from isolate: $data'); // 받은 메시지를 다시 보냄
});
}
이렇게 Isolate
를 활용하면 Dart에서도 병렬 처리가 가능하지만 그렇다고해서 이 방법이 Dart를 멀티 스레드 언어로 만들지는 않는다. 각 Isolate
는 메모리를 공유하지 않고 서로간의 통신은 sendPort
와 receivePort
를 이용한 메시지 패싱을 통해 이루어지게 되는데 이런 통신 방식은 전통적인 멀티 스레드 프로그래밍에서의 메모리 공유와는 다르게 동작하기 때문이다 요약하면 싱글 스레드 끼리의 통신일 뿐이란 얘기다
결국 Dart는 Isolate
통해 병렬 처리를 지원하긴 하지만, 기본적으로는 싱글 스레드 언어라는 점에는 변함이 없다
Isolate를 프로젝트에 도입하고 싶다면 사용후 제대로 닫아주는 것(Kill)이 앱 건강에 좋다.
참고 사이트
https://web.archive.org/web/20170704074724/https://webdev.dartlang.org/articles/performance/event-loop
https://medium.com/dartlang/dart-asynchronous-programming-isolates-and-event-loops-bffc3e296a6a
사용후 제대로 닫아주는 것(Kill)이 앱 건강에 좋다. >> 안 닫고 그대로 두면 영원히 살아있나요??