import 'dart:async';
void main() {
final controller = StreamController();
final stream = controller.stream;
final streamListener1 =
stream.listen((value) => print('Listener 1 : $value'));
controller.sink.add(1);
controller.sink.add(2);
controller.sink.add(3);
controller.sink.add(4);
controller.sink.add(5);
}
이 Dart 코드는 StreamController
를 생성하고 이를 사용하여 스트림에 데이터를 추가한 후, 한 리스너가 해당 데이터를 수신하도록 설정하고 있습니다. 각 코드 부분의 기능은 다음과 같습니다:
StreamController
: 스트림을 생성하고 데이터를 추가하는 방법을 제공하는 객체입니다. 컨트롤러는 데이터를 추가하는 sink
와 데이터를 수신하는 stream
을 가지고 있습니다.
stream
: 데이터가 추가될 실제 스트림입니다. StreamController
에서 얻은 스트림으로, 리스너가 구독하여 데이터를 수신할 수 있습니다.
streamListener1
: 스트림에 대한 구독입니다. 스트림에 listen
을 호출하면 구독이 생성됩니다. 여기서는 스트림이 새로운 데이터를 발행할 때 수행할 작업을 정의하고 있습니다. 이 경우 'Listener 1 :'이라는 접두사와 함께 데이터를 출력합니다.
controller.sink.add(value)
: 스트림에 데이터를 추가하는 방법입니다. sink
는 스트림의 입력 부분이며, 여기서는 1부터 5까지의 숫자를 추가하고 있습니다.
프로그램의 흐름은 다음과 같습니다:
StreamController
가 생성됩니다.StreamController
로부터 stream
을 얻습니다.stream.listen(...)
으로 stream
에 구독합니다.controller.sink.add(value)
를 사용하여 스트림에 값(1에서 5까지)을 추가합니다.프로그램이 실행되면 controller.sink.add
를 통해 추가된 각 숫자가 스트림을 통해 발행되고, streamListener1
에 의해 출력됩니다. 여기서는 하나의 리스너만 있으므로 각 값이 스트림에 추가될 때마다 그 값이 출력됩니다.
Dart에서 Stream
이라는 이름은 연속적인 데이터의 흐름을 의미합니다. 데이터 스트림은 여러 개의 데이터 이벤트를 순차적으로 제공하는 시퀀스입니다. 이런 면에서 보면, 실제로 물이 흐르는 'stream'과 비슷한 개념으로 생각할 수 있습니다: 데이터가 시간에 따라 흘러가며, 구독자는 그 데이터를 받아 처리할 수 있습니다.
sink
메서드는 Stream
에 데이터를 "넣는" 역할을 합니다. 실세계에서의 "sink"는 물이나 다른 물질이 들어가는 장소를 의미하는데, 이 경우 프로그래밍에서의 sink
는 데이터 스트림에 데이터를 "배출"하는 입력 지점을 의미합니다. StreamController
의 sink
는 데이터를 스트림으로 푸시하는 인터페이스 역할을 하며, 이 데이터는 후에 스트림을 구독하고 있는 리스너들에 의해 소비됩니다.
간단히 말해서, Stream
은 데이터의 흐름을 나타내고, sink
는 그 흐름에 데이터를 추가하는 메커니즘을 제공합니다. Dart의 스트림은 비동기 프로그래밍에서 중요한 역할을 하며, 데이터가 연속적으로 생성되고 처리되는 다양한 시나리오에서 사용됩니다.
콘솔에 출력된 값은 다음과 같습니다.
Listener 1 : 1
Listener 1 : 2
Listener 1 : 3
Listener 1 : 4
Listener 1 : 5
import 'dart:async';
void main() {
final controller = StreamController();
final stream = controller.stream.asBroadcastStream();
final streamListener1 =
stream.listen((value) => print('Listener 1 : $value'));
final streamListener2 =
stream.listen((value) => print('Listener 2 : $value'));
controller.sink.add(1);
controller.sink.add(2);
controller.sink.add(3);
controller.sink.add(4);
controller.sink.add(5);
}
이 Dart 코드 조각은 StreamController
를 사용하여 방송 스트림(broadcast stream)을 만들고, 두 개의 리스너로 해당 스트림을 구독하는 방법을 보여줍니다. 방송 스트림은 여러 개의 리스너가 동시에 동일한 데이터 시퀀스를 받을 수 있도록 합니다.
다음은 이 코드가 수행하는 작업의 단계별 설명입니다:
StreamController
인스턴스를 생성합니다. 기본적으로 스트림 컨트롤러는 단일 구독 스트림(single-subscription stream)을 생성합니다. 이는 한 번에 하나의 리스너만을 허용하는 스트림을 의미합니다.
.asBroadcastStream()
메서드를 호출하여 방송 스트림으로 변환합니다. 이렇게 하면 여러 리스너가 스트림에 구독할 수 있게 됩니다.
첫 번째 리스너(streamListener1
)를 등록하여 스트림의 데이터를 수신하고 출력합니다.
두 번째 리스너(streamListener2
)를 등록하여 동일한 스트림의 데이터를 동시에 수신하고 출력합니다.
controller.sink.add()
메서드를 사용하여 스트림에 숫자 1부터 5까지의 데이터를 순차적으로 추가합니다.
각 데이터 항목이 스트림에 추가될 때마다, 모든 구독된 리스너들은 그 데이터를 받고 출력합니다. 따라서 이 코드의 출력은 다음과 같을 것입니다:
Listener 1 : 1
Listener 2 : 1
Listener 1 : 2
Listener 2 : 2
Listener 1 : 3
Listener 2 : 3
Listener 1 : 4
Listener 2 : 4
Listener 1 : 5
Listener 2 : 5
리스너의 실제 출력 순서는 시스템의 스케줄링과 Dart의 이벤트 루프에 따라 달라질 수 있지만, 위의 순서대로 출력되는 것이 일반적입니다.
import 'dart:async';
void main() {
final controller = StreamController();
final stream = controller.stream.asBroadcastStream();
final streamListener1 = stream
.where((value) => value % 2 == 0)
.listen((value) => print('Listener 1 : $value'));
final streamListener2 = stream
.where((value) => value % 2 == 1)
.listen((value) => print('Listener 2 : $value'));
controller.sink.add(1);
controller.sink.add(2);
controller.sink.add(3);
controller.sink.add(4);
controller.sink.add(5);
}
이 코드는 Dart의 스트림과 함께 필터링 연산을 수행하는 방법을 보여줍니다. 두 리스너는 .where()
메서드를 사용하여 서로 다른 조건에 따라 데이터를 필터링합니다.
streamListener1
은 짝수 값만 받아서 출력합니다 (value % 2 == 0
). streamListener2
는 홀수 값만 받아서 출력합니다 (value % 2 == 1
).
코드가 수행되면 다음과 같은 작업이 일어납니다:
StreamController
가 생성되고, stream
변수는 이 컨트롤러의 스트림을 참조합니다.asBroadcastStream()
을 호출하여 방송 스트림을 생성합니다, 이렇게 함으로써 여러 리스너가 동시에 스트림에 구독할 수 있습니다.streamListener1
과 streamListener2
는 스트림을 필터링하고, 각각 짝수와 홀수만을 수신하도록 설정됩니다.controller.sink.add()
를 통해 스트림에 데이터를 추가합니다. 각 데이터 항목은 해당하는 리스너에 의해 수신되고 출력됩니다.이 코드가 실행될 때, 출력은 다음과 같을 것입니다:
Listener 2 : 1
Listener 1 : 2
Listener 2 : 3
Listener 1 : 4
Listener 2 : 5
각 리스너는 설정된 필터 조건에 맞는 데이터만을 수신합니다. 여기서는 streamListener1
이 짝수를, streamListener2
가 홀수를 출력합니다.
import 'dart:async';
void main() {
calculate(1).listen((value) => print('calculate(1) : $value'));
}
Stream<int> calculate(int number) async* {
for (int i = 0; i < 5; i++) {
yield i * number;
}
}
이 Dart 코드는 비동기 스트림 생성과 비동기 반복(async*
) 및 yield
키워드를 사용하여 스트림에 값을 방출하는 방법을 보여줍니다. calculate
함수는 주어진 숫자(number
)로 0부터 4까지의 숫자를 곱하여 스트림을 통해 방출합니다.
여기서 calculate
함수는 async*
를 사용하여 정의됩니다. 이는 함수가 비동기 스트림을 반환할 것임을 나타냅니다. 함수 내에서 yield
키워드는 스트림에 값을 하나씩 방출합니다. 이 함수는 0부터 시작하여, 매 반복마다 i
를 입력 파라미터인 number
와 곱한 결과를 스트림에 방출합니다.
main
함수에서는 calculate
함수에 1
을 인자로 넘겨 호출하고, 반환된 스트림에 리스너를 등록합니다. 이 리스너는 스트림에서 새 값을 받을 때마다 해당 값을 콘솔에 출력합니다.
코드 실행 결과는 다음과 같습니다:
calculate(1) : 0
calculate(1) : 1
calculate(1) : 2
calculate(1) : 3
calculate(1) : 4
각 출력은 calculate
함수에서 생성된 스트림에 yield
로 추가된 값입니다. 여기서는 0부터 4까지의 값을 각각 1(함수 호출 시 주어진 number
)과 곱한 값이 출력됩니다.
Dart에서 yield
와 async*
키워드는 스트림을 생성하고 관리하는 데 사용됩니다. 이들은 비동기 프로그래밍에서 중요한 역할을 하며, 특히 데이터를 연속적으로 생성하고 소비하는 경우에 유용합니다.
import 'dart:async';
void main() {
calculate(1).listen((value) => print('calculate(1) : $value'));
calculate(2).listen((value) => print('calculate(2) : $value'));
}
Stream<int> calculate(int number) async* {
for (int i = 0; i < 5; i++) {
yield i * number;
await Future.delayed(Duration(seconds: 1));
}
}
이 코드는 Dart 프로그래밍 언어의 비동기 스트림 생성과 관련이 있습니다. Dart에서 async*
와 yield
키워드는 비동기 스트림 생성자를 정의하는 데 사용됩니다.
아래는 코드의 주요 부분에 대한 설명입니다:
async*
:
async*
키워드는 비동기 스트림 생성자를 나타냅니다. 이는 함수가 Stream
을 반환하며 스트림에 여러 이벤트를 비동기적으로 추가할 수 있음을 의미합니다.yield
:
yield
키워드는 스트림에 값을 추가합니다. 이 코드에서는 for 루프를 통해 0부터 4까지 순회하면서 number
변수에 i
를 곱한 값을 스트림에 추가합니다.await Future.delayed
:
await
키워드와 함께 사용되는 Future.delayed
는 비동기 지연을 생성합니다. 이 경우 각 이벤트 사이에 1초의 지연을 추가하여, 스트림 소비자가 새 값을 받기까지 1초씩 기다립니다.calculate(1).listen
과 calculate(2).listen
:
main
함수에서는 calculate
함수를 두 번 호출하여 두 개의 스트림을 생성하고, 각각의 스트림에 대해 listen
메소드를 호출하여 값을 출력합니다. 이 메소드는 스트림에서 값을 받을 때마다 콜백 함수를 실행합니다.결과적으로 이 코드는 두 개의 비동기 스트림을 생성하고, 각 스트림은 1초 간격으로 0부터 4까지의 숫자를 받은 number
로 곱한 값을 생성합니다. 첫 번째 스트림은 1을 곱한 값들(0, 1, 2, 3, 4)을, 두 번째 스트림은 2를 곱한 값들(0, 2, 4, 6, 8)을 출력합니다.
async*
키워드는 비동기 스트림 생성기를 나타냅니다. async*
를 함수에 사용하면 함수는 Stream
을 반환하게 되며, 이 스트림은 비동기적으로 여러 값을 방출할 수 있습니다. async*
로 정의된 함수 내부에서는 yield
와 yield*
를 사용해 값을 스트림에 추가할 수 있습니다.
yield
키워드는 async*
함수에서 사용됩니다. 이 키워드는 스트림에 단일 값을 추가하고, 스트림의 소비자에게 값을 제공합니다. 스트림의 리스너는 yield
를 통해 방출된 각 값에 대해 지정된 콜백을 실행합니다. yield
다음에 오는 표현식이 평가되면 그 값은 스트림의 구독자에게 전송되고, 함수의 실행은 다음 yield
가 호출되거나 스트림이 닫힐 때까지 일시 중단됩니다.
Stream<int> countStream(int to) async* {
for (int i = 1; i <= to; i++) {
yield i; // 스트림에 i 값을 추가한다.
}
}
위 예제에서 countStream
함수는 주어진 to
값까지 숫자를 방출하는 스트림을 생성합니다. 호출자는 이 스트림을 구독하고, yield
를 통해 방출된 각 값에 대한 액션을 수행할 수 있습니다.
yield*
는 다른 비동기 스트림의 모든 값을 현재 스트림에 추가하는 데 사용됩니다. yield*
다음에 오는 스트림의 모든 값이 현재 스트림에 방출되어, 두 스트림이 하나로 연결되는 효과가 있습니다.
Stream<int> countStream(int to) async* {
if (to > 0) {
// 재귀적으로 countStream을 호출하고 현재 스트림에 모든 값을 추가한다.
yield* countStream(to - 1);
}
yield to;
}
위 예제에서는 yield*
를 사용하여 재귀적으로 스트림을 구성하고 있습니다. 각 재귀 호출에서 현재까지의 스트림에 to - 1
까지의 값을 추가하고, 마지막에 to
값을 스트림에 추가합니다.
이러한 방식으로 async*
와 yield
는 Dart의 비동기 프로그래밍에서 강력한 도구로 작용하여, 복잡한 비동기 데이터 스트림을 쉽고 효율적으로 생성하고 관리할 수 있게 합니다.
import 'dart:async';
void main() {
playAllStream().listen((value) => print(value));
}
Stream<int> playAllStream() async* {
yield* calculate(1);
yield* calculate(1000);
}
Stream<int> calculate(int number) async* {
for (int i = 0; i < 5; i++) {
yield i * number;
await Future.delayed(Duration(seconds: 1));
}
}
이 코드는 calculate
스트림을 이용해 두 개의 스트림을 연결하는 playAllStream
이라는 새로운 비동기 스트림 생성자를 만들고 있습니다. 각 calculate
스트림은 숫자를 0부터 4까지 순회하면서 해당 숫자에 매개변수로 받은 number
값을 곱해 이벤트를 발생시킵니다. 각 이벤트는 1초 간격으로 발생합니다.
주요 부분은 다음과 같습니다:
playAllStream
함수:
async*
키워드를 사용하여 정의된 비동기 스트림 생성자입니다. yield*
표현은 다른 스트림의 모든 이벤트를 현재 스트림으로 전달합니다. yield* calculate(1);
과 yield* calculate(1000);
:
calculate(1)
스트림에서 발생하는 모든 이벤트를 playAllStream
스트림으로 전달합니다. calculate(1000)
스트림의 이벤트를 전달합니다.calculate
함수:
async*
를 사용하여 정의된 비동기 스트림 생성자입니다. number
값을 곱한 결과를 스트림에 추가합니다.await Future.delayed
를 통해 각 이벤트 발생 사이에 1초의 지연이 있습니다.결과적으로 playAllStream
을 구독하는 리스너는 calculate(1)
에서 발생하는 모든 이벤트(0, 1, 2, 3, 4)를 순차적으로 받고, 그 다음에 calculate(1000)
에서 발생하는 이벤트(0, 1000, 2000, 3000, 4000)를 순차적으로 받게 됩니다. 각각의 yield
이벤트 사이에는 1초의 지연이 있습니다.