[Dart] stream sync*, async*, yield, yield* 차이점

비동기 프로그래밍을 할 때 async/await 형식을 많이 이용합니다. async와 같이 똑같이 비동기 프로그래밍이지만 stream을 반환할 때에는 async*을 사용하게 됩니다.

stream은 비동기로 발생하는 데이터를 수신하기 위해서 사용합니다.

stream은 데이터를 생성하는 부분과 이를 수신하여 사용하는 부분을 분리합니다.

이 데이터를 생성하는 부분을 생성함수(generator functions)라고 지칭합니다.

함수를 만들 때 사용하는 async*나 sync* 키워드는 바로 이런 생성함수를 만들기 위해서 사용하는 키워드입니다.

생성함수는 동기식과 비동기식으로 나눌 수 있는데 비동기식은 값을 stream으로 내보내는 것을 의미하며, 동기식은 데이터를 iterable 형태로 내보냅니다.

함수를 사용할 때 값을 내보내기 위해서 return을 사용하였지만 stream에서는 yield를 이용합니다. yield는 단일 값을 return하지만 “생성함수를 종료하지 않습니다.”

생성함수의 특징은 값을 다른 listener의 요청이 발생한 시점에 생성한다는 것입니다. 외부로부터의 요청이 없으면 값을 발생시키지 않습니다. 이를 게으른 데이터 연산(lazily produce)이라고 지칭하며 미리 연산을 다 하지 않고 요청이 있을 때까지 연산을 미뤄두었다가 필요 시 처리함을 의미합니다.

sync*

void main() {
  print('create iterator');
  Iterable<int> numbers = getNumbers(3);
  print('starting to iterate...');
  for (int val in numbers) {
    print('$val');
  }
  print('end of main');
}
Iterable<int> getNumbers(int number) sync* {
  print('generator started');
  for (int i = 0; i < number; i++) {
    yield i;
  }
  print('generator ended');
}

async*

void main() {
  print('create iterator');
  Stream<int> numbers = getNumbers(3);
  print('starting to listen...');
  numbers.listen((int value) {
    print('$value');
  });
  print('end of main');
}
Stream<int> getNumbers(int number) async* {
  print('waiting inside generator a bit :)');
  await new Future.delayed(new Duration(seconds: 5)); //sleep 5s
  print('started generating values...');
  for (int i = 0; i < number; i++) {
    await new Future.delayed(new Duration(seconds: 1)); //sleep 1s
    yield i;
  }
  print('ended generating values...');
}

yield*는 재귀생성함수를 반환할 때 사용합니다.

void main() {
  print('create iterator');
  Iterable<int> numbers = getNumbersRecursive(3);
  print('starting to iterate...');
  for (int val in numbers) {
    print('$val');
  }
  print('end of main');
}
Iterable<int> getNumbersRecursive(int number) sync* {
  print('generator $number started');
if (number > 0) {
    yield* getNumbersRecursive(number - 1);
  }
  yield number;
print('generator $number ended');
}

REFERENCES

https://jelenaaa.medium.com/what-are-sync-async-yield-and-yield-in-dart-defe57d06381

https://funncy.github.io/programming/2020/09/04/async-yield/

Leave a Comment