Dart Stream과 yield

이 문서 주변 탐색

주제 태그, 링크, 시리즈 흐름을 중심으로 옆으로 이동할 수 있습니다.

시리즈 흐름

이 문서는 아직 읽기 시리즈에 연결되지 않았습니다.

관련 문서

같이 읽을 만한 관련 문서가 아직 없습니다.

이 문서를 참조하는 문서

이 문서를 참조하는 다른 문서가 아직 없습니다.

1. 핵심 개념: 한 번에 vs 하나씩

프로그래밍에서 데이터를 받는 방식은 크게 두 가지임

방식 1: 한 번에 받기 (Future)

요청 → 기다림 → 결과 1개 도착 → 끝!

방식 2: 하나씩 계속 받기 (Stream)

구독 시작 → 데이터1 도착 → 데이터2 도착 → ... → 스트림 종료

2. 일상 비유로 이해하기

🍕 Future = 피자 배달

1. 피자 주문함
2. 배달 기다림
3. 피자 1판 도착
4. 끝!
  • 한 번하나의 결과만 받음

  • 결과 받으면 거래 끝

// Future 예시
Future<String> orderPizza() async {
  await Future.delayed(Duration(minutes: 30));
  return '페퍼로니 피자';  // 한 번 반환하고 끝
}

🏭 Stream = 공장 컨베이어 벨트

1. 공장 가동 시작
2. 제품 1번 나옴 → 받음
3. 제품 2번 나옴 → 받음
4. 제품 3번 나옴 → 받음
5. ... (계속)
6. 공장 멈춤 → 끝
  • 데이터가 연속으로 나옴

  • 언제 끝날지 모름 (계속 나올 수도 있음)

  • 구독하고 있어야 받을 수 있음

// Stream 예시
Stream<String> factoryBelt() async* {
  yield '제품 1번';  // 내보내고 계속
  yield '제품 2번';  // 내보내고 계속
  yield '제품 3번';  // 내보내고 끝
}

🎬 또 다른 비유들

Future

Stream

영화 다운로드 (완료되면 한번에 받음)

넷플릭스 스트리밍 (조금씩 계속 받음)

택배 배송 (한 번에 도착)

정기 구독 서비스 (매달 도착)

사진 1장 찍기

동영상 촬영 (프레임이 계속 나옴)

전화 통화 (한 번 연결)

라디오 방송 (계속 송출)

3. 코드 한 줄씩 뜯어보기

원본 코드

import 'dart:async';

void main() {
  calculate(2).listen((val){
    print('calculate(1) : $val');
  });
}

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

3.1 Stream 만드는 함수 분석

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

코드

의미

Stream<int>

"정수(int)를 여러 개 내보내는 스트림을 반환할거야"

calculate(int number)

"number라는 숫자를 받아서 계산할거야"

async*

"이 함수는 스트림 생성기야" ⭐ 별표(*) 중요!

for(int i = 0; i < 5; i++)

"i를 0부터 4까지 5번 반복해"

yield i * number

"i × number 계산 결과를 내보내고, 멈추지 말고 다음으로"

3.2 Stream 구독하기 분석

calculate(2).listen((val){
  print('결과: $val');
});

코드

의미

calculate(2)

"2를 넣고 스트림 만들어"

.listen(...)

"스트림 구독 시작! 값 나올 때마다 알려줘"

(val){...}

"값이 나오면 val에 넣고 중괄호 안 코드 실행해"

print('결과: $val')

"결과: (나온 값)" 출력

3.3 실행 결과

결과: 0    (i=0, 0 × 2 = 0)
결과: 2    (i=1, 1 × 2 = 2)
결과: 4    (i=2, 2 × 2 = 4)
결과: 6    (i=3, 3 × 2 = 6)
결과: 8    (i=4, 4 × 2 = 8)

4. return vs yield 차이

return (일반 함수)

int getNumber() {
  return 1;    // 1 반환하고 함수 완전히 끝!
  return 2;    // ❌ 절대 여기 도달 못함
  return 3;    // ❌ 절대 여기 도달 못함
}

void main() {
  print(getNumber());  // 1만 출력됨
}

return의 특징:

  • 값을 반환하면 함수 즉시 종료

  • 그 아래 코드는 실행 안 됨

  • 한 번만 값을 줄 수 있음

yield (스트림 생성기)

Stream<int> getNumbers() async* {
  yield 1;    // 1 내보내고 잠깐 멈춤, 다음 줄로
  yield 2;    // 2 내보내고 잠깐 멈춤, 다음 줄로
  yield 3;    // 3 내보내고 함수 끝
}

void main() {
  getNumbers().listen((n) => print(n));
  // 1 출력
  // 2 출력
  // 3 출력
}

yield의 특징:

  • 값을 내보내도 함수 계속 진행

  • 아래 코드도 계속 실행됨

  • 여러 번 값을 줄 수 있음

핵심 차이 정리

구분

return

yield

함수 종료

즉시 종료

계속 진행

값 개수

1개만

여러 개

사용처

일반 함수

async* 함수

비유

"받아! 끝!"

"받아! 더 있어!"

5. 실제 사용 예시

예시 1: 카운트다운

// 5, 4, 3, 2, 1, 발사!
Stream<String> countdown() async* {
  for (int i = 5; i >= 1; i--) {
    yield '$i...';
    await Future.delayed(Duration(seconds: 1));  // 1초 대기
  }
  yield '발사! 🚀';
}

void main() {
  countdown().listen((msg) => print(msg));
}

// 출력 (1초 간격으로):
// 5...
// 4...
// 3...
// 2...
// 1...
// 발사! 🚀

예시 2: 파일 다운로드 진행률

Stream<int> downloadProgress() async* {
  for (int percent = 0; percent <= 100; percent += 10) {
    yield percent;
    await Future.delayed(Duration(milliseconds: 500));
  }
}

void main() {
  downloadProgress().listen((percent) {
    print('다운로드 중... $percent%');
  });
}

// 출력:
// 다운로드 중... 0%
// 다운로드 중... 10%
// 다운로드 중... 20%
// ...
// 다운로드 중... 100%

예시 3: 채팅 메시지 시뮬레이션

Stream<String> chatMessages() async* {
  await Future.delayed(Duration(seconds: 1));
  yield '👤 철수: 안녕!';

  await Future.delayed(Duration(seconds: 2));
  yield '👤 영희: 반가워~';

  await Future.delayed(Duration(seconds: 1));
  yield '👤 철수: 뭐해?';
}

void main() {
  chatMessages().listen((message) {
    print(message);
  });
}

예시 4: 실시간 주식 가격

import 'dart:math';

Stream<int> stockPrice() async* {
  int price = 50000;  // 시작 가격

  while (true) {  // 무한 스트림
    // -500 ~ +500 사이 랜덤 변동
    price += Random().nextInt(1001) - 500;
    yield price;
    await Future.delayed(Duration(seconds: 1));
  }
}

void main() {
  // 10번만 받고 종료
  stockPrice().take(10).listen((price) {
    print('현재 주가: ${price}원');
  });
}

6. 핵심 정리

키워드 정리표

키워드

의미

비유

Future

미래에 받을 값 1개

택배 1개

Stream

계속 흘러나오는 값들

컨베이어 벨트

async

"비동기 함수야"

"잠깐 기다릴 수도 있어"

async*

"스트림 생성기야"

"값을 여러 개 줄 거야"

await

"기다려"

"택배 올 때까지 대기"

yield

"이거 내보내"

"벨트에 제품 올림"

.listen()

"구독할게"

"벨트 앞에서 대기"

async vs async* 비교

구분

async

async*

반환 타입

Future<T>

Stream<T>

값 내보내기

return

yield

값 개수

1개

여러 개

완료 시점

return 시

함수 끝날 때

Stream이 필요한 상황

상황

설명

채팅 앱

메시지가 언제 올지 모름

주식 앱

가격이 실시간으로 변함

다운로드

진행률이 계속 업데이트됨

GPS

위치가 계속 바뀜

센서

데이터가 계속 들어옴

검색 자동완성

입력마다 결과 바뀜

🤖

본 글은 AI의 도움을 받아 작성되었습니다.

읽기 시리즈

현재 위치를 확인하고, 흐름을 따라 바로 다음 읽기로 이어갈 수 있습니다.

Reading Series

Dart
0편

현재 읽는 문서

Dart Stream과 yield

Dart 언어에 대해서 알아보기

이전 문서

시리즈의 시작 문서입니다.

다음 문서

시리즈의 마지막 문서입니다.