Thread

프로세스 내에서 실행되는 흐름의 단위

Event loop

Dart는 Single Thread로 운영됨 → Event loop를 통해 복잡한 작업들을 효율적으로 처리

Flutter 앱을 실행시키는 순간 isolate라고 불리는 새로운 thread process가 하나 생성됨

이 thread가 앱 전체를 총괄하는 단일 thread가 됨

thread가 생성되는 순간 dart는 자동적으로 3가지 작업을 하게됨

  1. 내부적으로 First In First Out(FIFO)방식으로 MicroTask 와 Event 준비 MicroTask : event queue로 넘어가기 전에 아주 짧은 시간 동안 비동기적으로 먼저 실행되고 끝나는 작은 작업
  2. 앱의 시작점인 main 함수 실행
  3. Event loop 실행

Dart는 하나의 단일 thread가 실행되는 순간 내부적으로 event loop process를 통해 순서대로 대기열에 있는 micro task와 event를 처리

더 이상 내부적으로 진행할 micro task가 없다면 event loop는 외적으로 전달되는 각종 이벤트 (gesture, drawing, reading files, fetching data, button tap, future, stream 등)를 순서대로 처리하게 됨

각종 외적인 이벤트들이 이벤트 큐에 등록되고 이벤트 루프를 통해 처리

Future

비동기 방식으로 미래의 어느시점에 완성되어서 실제적인 데이터가 되거나 에러를 반환하는 객체

코드상에서 새로운 future를 객체화 시키면

  1. 다트에 의해서 future 객체가 내부적인 배열에 등록
  2. Future 관련해서 실행되어야하는 코드들이 이벤트 큐(대기열)에 등록
  3. 불완전한 future 객체가 반환
  4. Synchronous 방식으로 실행되어야 할 코드 먼저 실행
  5. 최종적으로 실제적인 data 값이 future 객체로 전달

Async method

async 키워드를 사용한 순간

  1. 메서드를 통해서 나오는 결과물들은 future라는 것을 알게 됨
  2. await 키워드를 만날때까지 synchronous 방식으로 코드 처리
  3. await 키워드를 만나면 future가 완료될 때까지 대기
  4. future가 완료 되자마자 그 다음 코드들을 실행

전체 앱의 실행이 중지되지 않고 future 부분은 건너띄고 그 아래에 있는 코드들을 synchronous하게 처리

예시

String createOrderMessage(){
    var order = fetchUserOrder();
    return 'Your order is: $order';
}

Future<String> fetchUserOrder(){
    return Future.delayed(
        Duration(second: 2), ()=>'Large Latte',
    );
}

void main(){
    print('Fetching user order...');
    print(createOrderMessage());
}

실행시 에러 → main()의 두번째 print에서 createOrderMessage()는 미완성의 객체를 반환하고 있기 때문

fetchUserOrder()에서 2초를 기다리고 fetchUserOrder()가 반환해야 하는데 기다리지 않고 즉시 반환하기 때문 → 이를 해결하기 위해 async 키워드 사용

createOrderMessage() 수정

  1. 비동기 방식으로 실행된 결과의 String 값을 리턴해줘야하므로 타입 변경 String → Future
  2. order 변수에 fetchUserOrder 함수의 리턴값을 할당해줄려면 즉시할당하는 synchronous 방식이 아니라 기다렸다가 값이 전달되는 비동기 방식어야함 createOrderMessage()가 비동기 방식으로 처리되어야함을 dart에게 알려줘야함 → async 키워드 추가
  3. fetchUserOrder()의 실행이 끝날때까지 기다렸다가 order 변수에 값을 할당해줘야함 → await 추가
// 1
Future<String> createOrderMessage() async{ // 2
              // 3
    var order = await fetchUserOrder();
    return 'Your order is: $order';
}

main() 수정

  1. main()에서 호출되는 createOrderMessage()가 비동기 방식으로 처리되는 함수이므로 main()도 비동기 방식으로 처리됨을 알려줘야함 → async 추가
  2. createOrderMessage()의 리턴값이 출려되려면 order변수의 값이 할당될 때까지 기다려야함 → await 추가
// 1
void main() async{
    print('Fetching user order...');
    // 2
    print(await createOrderMessage());
}

정리

async 키워드는 future 자체를 대신하는 것이 아니라 비동기 방식으로 실행되는 함수라는 것을 dart에게 알려주는 기능을 하는 것이며 await 키워드와 함께 미래의 어느 시점에 전달될 값을 기다리는 것

future는 하나의 객체로서 객체가 생성되는 순간에는 미완성으로 존재하다가 미래의 어느 시점에 데이터를 전달받은 온전한 객체가 되거나 데이터에 문제가 생긴다면 에러를 반환

심화 예제

void main() async {
  methodA(); // 1
  await methodB(); // 3
  await methodC('main'); // 9
  methodD(); // 12
}

methodA(){
  print('A'); // 2
}

methodB() async {
  print('B start'); // 4
  await methodC('B'); // 5
  print('B end'); // 8
}

methodC(String from) async {
  print('C start from $from'); // 6 'b' // 10 'main'

  Future((){
    print('C running Future from $from'); // 14 'b' // 16 'main'
  }).then((_){
    print('C end of Future from $from'); // 15 'b' // 17 'main'
  });

  print('C end from $from'); // 7 'b' // 11 'main'
}

methodD(){
  print('D'); // 13
}

//////
A
B start
C start from B
C end from B
B end
C start from main
C end from main
D
C running Future from B
C end of Future from B
C running Future from main
c runngin Future from main
///

참고

https://www.youtube.com/watch?v=HjhPhAUPHos&list=PLQt_pzi-LLfoOpp3b-pnnLXgYpiFEftLB&index=12 

 

728x90

'Study > Dart' 카테고리의 다른 글

[Dart] factory 패턴  (0) 2021.06.24
[Dart] const 와 final 이해하기  (0) 2021.06.15
[Dart] Future, Isolate  (0) 2021.06.08
[Dart] 상속을 쓰는 이유  (0) 2021.06.07
[Dart] 상속  (0) 2021.06.07

+ Recent posts