[Flutter/Decoding Flutter] Async vs Isolates

작성 날짜:

최근 업데이트 날짜:

Decoding Flutter 유튜브 영상


AsyncIsolates의 개념은 언뜻 봤을 때 헷갈릴 수 있다. 이 두가지 개념은 각각 Concurrency(병행성)와 Parallelism(병렬성)로 표현할 수도 있다. ConcurrencyParallelism에 대해 이미 알고 있다면 바로 이해할 수 있을 것이다.

Async(Concurrency)

우선 Async에 대해서 정리해보자.

아래는 async를 사용한 asynchronous한 함수의 예시이다.

void _refresh() async {
  var url = _assembleUrl(options);
  var content = await http.get(url);
  var articles = _parse(content);
  _update(articles);
}

해당 코드는 위에서부터 차례로 실행하다가 두번째 줄(await이 들어간 부분)에서 파일이 다운되기를 기다린다. 그렇다면 이때 프로세스가 멈추고 아무 일도 하지 않는 것일까?

아니다. 해당 프로세스는 계속해서 일을 한다. 위의 예시에서 파일이 다운되는 동안, 프로세스는 멈추지 않고 _refresh() 함수 밖의 코드를 실행시킨다. 이후에 파일 다운로드가 완료되면 _refresh() 다시 돌아와 다음 코드를 실행시킨다.

여기서 Async는 자동으로 어플을 멀티쓰레드로 만들어주지 않는다는 것을 알 수 있다.

대부분의 경우에는 Async면 충분하다. 하지만 많은 자원을 소비하는 경우에는 어떨까?

이전 코드를 다시 가져와보자.

void _refresh() async {
  var url = _assembleUrl(options);
  var content = await http.get(url);
  var articles = _parse(content);
  _update(articles);
}

만약 다운 받는 파일이 크다고 생각해보자. 그렇다면 해당 파일을 파싱할 때 소비되는 프로세스의 파워도 굉장히 커진다. 이 경우 어플이 정상적으로 부드럽게 돌아갈까?

Async 메소드 안에서의 자원 소비이니까 어플이 부드럽게 돌아갈 것이라고 생각할 수 있다. 하지만 이는 잘못된 생각이다. 파싱 작업(_parse(content))은 쓰레드를 계속 사용해야하는 작업이라서 프로세스를 놔주지 않기 때문이다.

따라서 파싱 작업 중에는 프로세스가 다른 작업을 진행할 수 없어서 UI가 refresh 되지 않고, 결국 어플은 버벅거리게 된다.

Isolate(Parallelism)

이러한 경우에 필요한 것이 바로 Parallelism이다. Dart에선 isolate를 통해 코드를 parallel하게 돌릴 수 있다.

다른 쓰레드, 다른 프로세스에 새로운 Dart 프로그램을 실행시키는 것이다. 이 때 각각의 isolate는 서로를 블록하지 않는다. 이렇게 isolate를 사용하면 무거운 작업을 하면서도 유저에게 부드러운 UI를 보여줄 수 있다.

이 글은 단순히 AsyncIsolate의 개념을 비교하기 위한 글이기 때문에, isolate를 구현하는 방법에 대해서는 다루지 않는다.

요약

Async는 블로킹(blocking) 없이 기다리는 것이다. 또한 새로운 쓰레드를 생성하지 않는다.

Isolate는 일을 parallel하게 진행하는 것이다. 각 isolate는 다른 isolate가 어떤 일을 하는지 신경쓰지 않는다. 각각 자신의 일을 진행한다.

댓글남기기