프로그래밍/플러터

다트 비동기 프로그래밍

스루나루 2024. 2. 10. 16:52
728x90
728x90

 

 

동기 / 비동기

https://dev-coco.tistory.com/46

 

- 동기 : 요청을 하면 응답을 받을 때 까지 기다림

- 비동기 : 요청을 한 후 대기하지 않고 다른 거 하다가 요청 오면 그거 받음 

 

 

Future

- 클래스 

- 미래 어떤 값을 받을 지 지정가능 

void main(){
  Future<String> name;    // 미래에 받을 String값
  Future<int> number;     // 미래에 받을 int값
  Future<bool> isOpened;  // 미래에 받을 boolean값
}

 

void main() {
  addNumbers(1, 1);
}

void addNumbers(int number1, int number2){
  print('$number1 + $number2 계산 시작!');

  // ➊ Future.delayed()를 사용하면 일정 시간 후에 콜백 함수를 실행할 수 있음
  Future.delayed(Duration(seconds: 3), (){
    print('$number1 + $number2 = ${number1 + number2}');
  });

  print('$number1 + $number2 코드 실행 끝');
}

- Future.delayed()라는 함수로 일정 시간 후에 이거 실행하겠다고 선언한거라 그 밑에거 처리하고 그 다음 요청받아서 결과가 아래처럼 됨 


1 + 1 계산 시작!
1 + 1 코드 실행 끝
1 + 1 = 2

 

 

async / await 

 

- 비동기로 cpu를 효율적으로 쓰도록 Future를 써서 할 수가 있지만 비동기를 동기처럼 동작 시키고 싶을 때가 있음

- 순서대로 실행 시키기 위해서 async . await 를 사용 

- async를 함수에 쓴다 = 해당 함수는 비동기 함수다 

void main() {
  addNumbers(1, 1);
}

// async 키워드는 함수 매개변수 정의와 바디 사이에 입력합니다.
void addNumbers(int number1, int number2) async {
  print('$number1 + $number2 계산 시작!');

  // await는 대기하고 싶은 비동기 함수 앞에 입력합니다.
  await Future.delayed(Duration(seconds: 3), (){
    print('$number1 + $number2 = ${number1 + number2}');
  });

  print('$number1 + $number2 코드 실행 끝');
}

- 함수에 asnyc지정 하고 함수 실행시 await를 사용해서 코드를 작성한 순서대로 실행

 

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

// async 키워드는 함수 매개변수 정의와 바디 사이에 입력합니다.
Future<void> addNumbers(int number1, int number2) async {
  print('$number1 + $number2 계산 시작!');

  // await는 대기하고 싶은 비동기 함수 앞에 입력합니다.
  await Future.delayed(Duration(seconds: 3), (){
    print('$number1 + $number2 = ${number1 + number2}');
  });

  print('$number1 + $number2 코드 실행 끝');
}

 

- addNumber()함수가 Future함수로 비동기 함수임 이거 실행하고 결과를 기다리지 않음 짜피 await도 없으니까 결과 기다리지 않고 addNumbers()함수를 2번 실행한 거임 

- delayed()가 끝나고 그 다음 요청 결과를 기다려서 화면에 출력됨 


1+ 1 계산 시작!
2 + 2 계산 시작!
1 + 1 = 2
1 + 1 코드 실행 끝
2 + 2 = 4
2 + 2 코드 실행 끝

 

동기적로 동작하길 원하면 함수 호출 시 await를 붙이자 

await는 비동기 함수에서만 쓸 수 있어서 async를 main에 써줌 

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

// async 키워드는 함수 매개변수 정의와 바디 사이에 입력합니다.
Future<void> addNumbers(int number1, int number2) async {
  print('$number1 + $number2 계산 시작!');

  // await는 대기하고 싶은 비동기 함수 앞에 입력합니다.
  await Future.delayed(Duration(seconds: 3), (){
    print('$number1 + $number2 = ${number1 + number2}');
  });

  print('$number1 + $number2 코드 실행 끝');
}

 


1+ 1 계산 시작!
1 + 1 = 2
1 + 1 코드 실행 끝
2 + 2 계산 시작!
2 + 2 = 4
2 + 2 코드 실행 끝

 

 

비동기 함수의 결과값을 반환 받기 

 

void main() async {
  final result = await addNumbers(1, 1);
  print('결괏값 $result');  // 일반 함수와 동일하게 반환값을 받을 수 있음
  final result2 = await addNumbers(2, 2);
  print('결괏값 $result2');
}

Future<int> addNumbers(int number1, int number2) async {
  print('$number1 + $number2 계산 시작!');

  await Future.delayed(Duration(seconds: 3), (){
    print('$number1 + $number2 = ${number1 + number2}');
  });

  print('$number1 + $number2 코드 실행 끝');

  return number1 + number2;
}

 

정리 : chatgpt

  1. await:
    • await는 비동기 함수 내에서만 사용될 수 있습니다.
    • await 키워드는 비동기 함수 호출 앞에 붙여 사용하며, 해당 함수의 실행이 완료될 때까지 현재 함수의 실행을 일시 중단합니다.
    • await 키워드를 사용하여 비동기 함수의 결과를 기다린 다음, 해당 결과를 반환하거나 변수에 할당할 수 있습니다.
    • await 키워드는 Future 객체나 비동기 함수의 반환 타입이 있는 다른 비동기 작업을 기다릴 때 사용됩니다.
  2. async:
    • async 키워드는 함수의 선언부에 추가되며, 해당 함수가 비동기 함수임을 나타냅니다.
    • 비동기 함수는 Future 객체를 반환하는 함수입니다.
    • async 함수 내에서는 await 키워드를 사용하여 비동기 작업의 실행을 기다릴 수 있습니다.
    • async 함수는 비동기 작업을 순차적으로 실행하면서 다른 작업들을 동시에 처리할 수 있습니다.

 

Stream

MustHave 코드팩토리의 플러터 프로그래밍 2판 97p

- Future는 단 한 번만 값을 받아내는 비동기

- Stream은 한번 listen때리면 지속적으로 모든 값들을 받아냄 

 

1. 기본 사용법

- dart:async 패키지 필요 

- StreamController가 필요 : 이 컨트롤러로 스트림을 가져올 수 있음 

- listen : 컨트롤러에서 값의 변화가 있는 경우 해당 값을 파라미터로 받아서 내부로직 실행 

 

import 'dart:async';

void main() {
  final controller = StreamController();  // StreamController 선언
  final stream = controller.stream;  // Stream 가져오기

  // Stream에 listen() 함수를 실행하면 값이 주입될 때마다 콜백 함수를 실행할 수 있습니다.
  final streamListener1 = stream.listen((val) {
    print(val);
  });

  // Stream에 값을 주입할 때는 sink.add() 함수를 실행하면 됩니다.
  controller.sink.add(1);
  controller.sink.add(2);
  controller.sink.add(3);
  controller.sink.add(4);
}

 

2. 브로드캐스팅 스트림 

- 스트림은 원래 한 번만 리슨 실행가능 

- 하나의 스트림을 만들고 여러번 리슨하고 싶을 때 브로드캐스트 스트림을 사용하면 됨 

 

import 'dart:async';

void main() {
  final controller = StreamController();

  // 여러 번 리슨할 수 있는 Broadcaste Stream 객체 생성
  final stream = controller.stream.asBroadcastStream();

  // 첫 listen() 함수
  final streamListener1 = stream.listen((val) {
    print('listening 1');
    print(val);
  });

  // 두 번째 listen() 함수
  final streamListener2 = stream.listen((val) {
    print('listening 2');
    print(val);
  });

  // add()를 실행할 때마다 listen()하는 모든 콜백 함수에 값이 주입됩니다.
  controller.sink.add(1);
  controller.sink.add(2);
  controller.sink.add(3);

}

- 컨트롤러에 데이터 변화가 있을 때 복수의 Listen함수에서 데이터 변화를 감지하고 내부 로직을 실행 


listening 1
1
listening 2
1
listening 1
2
listening 2
2
listening 1
3
listening 2
3

 

 

3. 함수로 스트림 반환하기 

-StreamController선언하지 않고도 스트림 반환 가능 

- Future반환하는 함수는 async쓰고 return으로 값 반환 

- Stream반환하는 함수는 asnyc* 쓰고 yield로 값 반환 

import 'dart:async';

// Stream을 반환하는 함수는 async*로 선언합니다.
Stream<String> calculate(int number) async* {
  for (int i = 0; i < 5; i++) {
    // StreamController의 add()처럼 yield 키워드를 이용해서 값 반환
    yield 'i = $i';
    await Future.delayed(Duration(seconds: 1));
  }
}

void playStream() {
  // StreamController와 마찬가지로 listen() 함수로 콜백 함수 입력
  calculate(1).listen((val) {
    print(val);
  });
}

void main() {
  playStream();
}

- 1초마다 값을 리턴하는 함수에 리슨 달아서 값 변화 관측하고 출력함 


i = 0
i = 1
i = 2
i = 3
i = 4

 

 

참고

“이 글은 골든래빗 《Must Have 코드팩토리의 플러터 프로그래밍 2판》의 스터디 내용 입니다.” 

 

 

728x90
728x90