EDOC/Flutter 스터디 (2025-1)

[1.3] 다트 비동기 프로그래밍

SpruceMoon 2025. 3. 29. 19:26

1. 동기 vs 비동기 프로그래밍

  • 동기(Synchronous) 방식은 어느 작업이 끝날 때까지 기다린 후 다음 작업을 실행한다.
  • 비동기(Asynchronous) 방식은 작업을 요청한 후 기다리지 않고 다음 코드를 바로 실행하며, 응답이 오면 그때 결과를 처리한다.

비동기 방식은 CPU 리소스를 효율적으로 활용할 수 있다는 장점이 있다.


2. Future

Future는 미래에 받을 값을 표현하는 객체이다. 다음과 같은 형태로 선언한다.

Future<String> name;
Future<int> number;
Future<bool> isOpened;

비동기 작업 예시로는 다음과 같은 코드가 있다.

void addNumbers(int number1, int number2) {
  print('$number1 + $number2 계산 시작!');
  Future.delayed(Duration(seconds: 3), () {
    print('$number1 + $number2 = ${number1 + number2}');
  });
  print('$number1 + $number2 코드 실행 끝');
}

이 코드는 3초 지연 후 결과를 출력하도록 되어 있지만, 실제 실행 순서는 계산 시작 → 코드 실행 끝 → 결과 출력 순서로 이루어지는다. 이유는 Future.delayed()가 비동기적으로 작동하기 때문이다.


3. async / await

async는 비동기 함수를 선언할 때 사용하고, await는 비동기 함수의 실행 결과를 기다리기 위해 사용한다.

Future<void> addNumbers(int number1, int number2) async {
  print('$number1 + $number2 계산 시작!');
  await Future.delayed(Duration(seconds: 3), () {
    print('$number1 + $number2 = ${number1 + number2}');
  });
  print('$number1 + $number2 코드 실행 끝');
}

해당 함수를 순차적으로 실행하고 싶을 경우 main() 함수에도 async를 붙이고, 각 호출 앞에 await를 붙이면 된다.

void main() async {
  await addNumbers(1, 1);
  await addNumbers(2, 2);
}

4. 비동기 함수에서 값 받기

비동기 함수에서도 값을 받을 수 있다.

Future<int> addNumbers(int number1, int number2) async {
  print('$number1 + $number2 계산 시작!');
  await Future.delayed(Duration(seconds: 3));
  print('$number1 + $number2 계산 끝');
  return number1 + number2;
}

void main() async {
  final result = await addNumbers(1, 1);
  print('결과: $result');
}

5. Stream

Future가 한 번만 값을 받는 비동기 작업에 적합하다면, Stream은 여러 개의 값을 지속적으로 받을 때 사용한다.

final controller = StreamController();
final stream = controller.stream;

stream.listen((val) {
  print(val);
});

controller.sink.add(1);
controller.sink.add(2);

6. Broadcast Stream

일반 Stream은 한 번만 listen() 할 수 있다. 여러 건에서 동시에 값을 받아야 할 경우 asBroadcastStream()을 사용한다.

final stream = controller.stream.asBroadcastStream();

stream.listen((val) {
  print('리스너 1: $val');
});

stream.listen((val) {
  print('리스너 2: $val');
});

7. 함수로 Stream 반환하기

Stream을 반환하는 함수를 만들기 위해서는 async* 키워드와 yield를 사용한다.

Stream<String> calculate(int number) async* {
  for (int i = 0; i < 5; i++) {
    yield 'i = $i';
    await Future.delayed(Duration(seconds: 1));
  }
}

void main() {
  calculate(1).listen((val) {
    print(val);
  });
}

8. 요약 정보

  1. 비동기 프로그래밍은 CPU 리소스를 효율적으로 사용할 수 있게 해주는다.
  2. Future는 한 번만 값을 받는 비동기 작업에 적합하다.
  3. async는 비동기 함수 정의, await는 비동기 함수의 실행을 기다린다.
  4. Stream은 여러 개의 값을 지속적으로 받을 때 사용한다.
  5. StreamController를 사용해 스트링을 지금 키로 조절할 수 있고, asBroadcastStream으로 여러 리스너에게 브로드캐스트할 수 있다.
  6. async*와 yield를 사용하면 함수에서 스트링을 지정할 수 있다.