본문 바로가기

CS/Flutter | Dart

Dart Asynchronous Programming - Stream, yield

Stream

import 'dart:async';

void main() {
  final controller = StreamController();
  final stream = controller.stream;
  
  final streamListener1 = stream.listen((val){
    print("Listener1: $val");
  });
  
  controller.sink.add(1);
  controller.sink.add(2);
  controller.sink.add(3);
}

Listener1: 1
Listener1: 2
Listener1: 3

 

stream은 dart언어에서 기본적으로 제공해주는 기능이 아니기 때문에 import 해줘야 함

 

dart의 비동기 프로그래밍은 Future, Stream 클래스로 주로 처리

 

Future: 즉시 완료되지 않는 계산

일반 함수가 결과 반환하는 경우 비동기 함수는 Future 반환하며 결과에 포함됨

결과가 준비되면 Future에 알려줌

 

Stream: 일련의 비동기 이벤트

요청 시 다음 이벤트 받는 대신, Stream이 준비되면 이벤트가 있음을 알려주는 비동기 Iterable과 같음

 

 

import 'dart:async';

void main() {
  final controller = StreamController();
  final stream = controller.stream.asBroadcastStream();
  
  final streamListener1 = stream.listen((val){
    print("Listener1: $val");
  });
  final streamListener2 = stream.listen((val){
    print("Listener2: $val");
  });
  
  controller.sink.add(1);
  controller.sink.add(2);
  controller.sink.add(3);
}

Listener1: 1
Listener2: 1
Listener1: 2
Listener2: 2
Listener1: 3
Listener2: 3

 

final stream = controller.stream.asBroadcastStream(); 여기에 asBroadcastStream()를 써주면 여러면 listening할 수 있는 stream 만들 수 있음

 

 

import 'dart:async';

void main() {
  final controller = StreamController();
  final stream = controller.stream.asBroadcastStream();

  // val이 짝수일 때
  final streamListener1 = stream.where((val) => val % 2 == 0).listen((val) {
    print("Listener1: $val");
  });

  // val이 홀수일 때
  final streamListener2 = stream.where((val) => val % 2 == 1).listen((val) {
    print("Listener2: $val");
  });

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

Listener2: 1
Listener1: 2
Listener2: 3

 

where()이용해 각각 홀수일 때/ 짝수일 때 출력하는 예시

 

 

import 'dart:async';

void main() {
  calc(1).listen((val) {
    print("calc: $val");
  });
}

Stream<int> calc(int number) async* {
  for (int i = 0; i < 5; i++) {
    yield i * number;
  }
}

calc: 0
calc: 1
calc: 2
calc: 3
calc: 4

 

Stream 사용하지 않으면 for loop 안의 return 에서 return해주게 되면 i=0일 때만 실행하고 끝나버림

-> 이건 이 함수의 한계라 어쩔 수 없음

 

Stream 사용하면 가능

Future<int> calc(int number) async 이렇게 Future을 사용해도 되지만 Stream 사용하려면,

Stream<int> calc(int number) async* 이렇게 *을 붙여주면 됨

그리고 return을 yield로 바꿔주면 됨

-> yield를 할 때마다 calc 함수를 listening하고 있는 listener에 값 뿌려줄 수 있음

 

 

import 'dart:async';

void main() {
  calc(1).listen((val) {
    print("calc: $val");
  });
}

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

calc: 0
calc: 1
calc: 2
calc: 3
calc: 4

 

Stream 이여도 await 그냥 똑같이 쓸 수 있음

그냥 async함수로 진행됨

 

 

import 'dart:async';

void main() {
  playAllStream().listen((val) {
    print(val);
  });
}

Stream<int> playAllStream()async*{
  yield* calc(1);
  yield* calc(1000);
}

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

0
1
2
3
4
0
1000
2000
3000
4000

 

yield: 값을 하나하나 순서대로 가져올 때 사용

yield*: 해당되는 Stream의 모든 값이 다 return될 때까지 기다림

 

 

 

 


Tiny Star