반응형

Dart, 비동기 지원 (Asynchrony)

 

글, 수알치 오상문

 

Dart 라이브러리는 Future 또는 Stream 객체를 반환하는 함수로 가득합니다. 이러한 함수는 비동기입니다. 작업이 완료 될 때까지 기다리지 않고 시간이 많이 걸리는 작업(예: I/O)을 설정 한 후 반환됩니다. async 및 await 키워드는 비동기 프로그래밍을 지원하므로 동기 코드와 유사한 비동기 코드를 작성할 수 있습니다.

 

Futures 제어 

 

완료된 Future 결과가 필요할 때, 두 가지 선택이 있습니다.

async 및 await를 사용하는 코드는 비동기 적이지만 동기 코드와 비슷합니다. 예를 들어 다음은 비동기 함수의 결과를 기다리는 데 await를 사용하는 일부 코드입니다.

 

await lookUpVersion();

 

await를 사용하려면, 코드가 async 함수에 있어야 합니다.

 

Future<void> checkVersion() async {

  var version = await lookUpVersion(); // Do something with version

}

 

참고: 비동기 함수는 시간이 많이 걸리는 작업을 수행 할 수 있지만 이 작업을 기다리지 않습니다. 대신 async 함수는 첫 번째 await 식을 만날 때까지만 실행됩니다. 그 다음 Future 객체를 반환하고 await 표현식이 완료된 후에 ​​실행을 재개합니다. 

 

try, catch 및 finally 구조를 사용하여 await를 사용하는 코드에서 오류를 처리합니다.

 

try {

  version = await lookUpVersion();

} catch (e) {

  // 버전을 찾을 수없는 경우 이곳에서 처리...

}

 

비동기 함수에서 await를 여러 번 사용할 수 있습니다. 예를 들어 다음 코드는 함수 결과를 세 번 기다립니다.

 

var entrypoint = await findEntryPoint();

var exitCode = await runExecutable(entrypoint, args);

await flushThenExit(exitCode);

 

await 표현식에서 식의 값은 일반적으로 Future입니다. 그렇지 않은 경우 값이 Future로 자동 래핑됩니다. 이 Future 객체는 객체를 반환하겠다는 약속을 나타냅니다. await 표현식의 값은 반환된 객체입니다. await 식은 해당 개체를 사용할 수있을 때까지 실행을 일시 중지합니다.

 

await를 사용할 때 컴파일 시간 오류가 발생하면 await가 비동기 함수에 있는지 확인하세요. 예를 들어 앱의 main() 함수에서 await를 사용하려면 main()을 async로 지시해야합니다.

 

Future<void> main() async {

  checkVersion();

  print('In main: version is ${await lookUpVersion()}');

}

 

비동기 함수 선언

 

비동기 함수는 async로 표시된 함수입니다. 함수에 async 예약어를 추가하면 Future가 반환됩니다. 예를 들어, 문자열을 반환하는 다음과 같은 동기 함수가 있습니다.

 

String lookUpVersion() => '1.0.0';

 

만약 향후에 시간이 많이 걸리기 때문에 비동기 함수로 변경하면 반환 값은 Future입니다.

 

Future<String> lookUpVersion() async => '1.0.0';

 

함수의 본문은 Future API를 사용할 필요가 없습니다. Dart는 필요한 경우에 Future 객체를 생성합니다. 함수가 유용한 값을 반환하지 않으면 반환 유형을 Future <void>로 설정합니다.

 

Future, async, await에 대한 비동기 프로그래밍 코드 랩 참조: asynchronous programming codelab.

 

스트림 제어

 

Stream에서 값을 가져와야하는 경우 두 가지 선택이 있습니다.

  • 비동기 및 비동기 for 루프(await for) 사용
  • Stream API 사용 (참조: in the library tour)

참고: await for를 사용하기 전에 코드가 명확한지, 스트림의 모든 결과를 기다리고 싶은지 확인합니다. 예를 들어, UI 프레임워크는 끝없는 이벤트 스트림을 전송하므로 일반적으로 UI 이벤트 리스너(listener)에 대해 await를 사용하지 않습니다.

 

비동기 for 루프의 형식은 다음과 같습니다.

 

await for (varOrType identifier in expression) {

  // 스트림이 값을 내보낼 때마다 실행됨

}

 

expression 값은 Stream 유형이어야합니다. 실행은 다음과 같이 진행됩니다.

  1. 스트림이 값을 내보낼 때까지 대기
  2. 방출된 값으로 설정된 변수를 사용하여 for 루프의 본문을 실행.
  3. 스트림이 닫힐 때까지 1, 2를 반복합니다.

스트림 수신을 중지하려면 break 또는 return 문을 사용할 수 있습니다. 

 

비동기 for 루프를 구현할 때 컴파일 타임 오류가 발생하면 await for가 비동기 함수에 있는지 확인하세요. 예를 들어 앱의 main() 함수에서 비동기 for 루프를 사용하려면 main() 함수는 async로 표시해야 합니다.

 

Future<void> main() async {

  // ...

  await for (var request in requestServer) {

    handleRequest(request);

  }

  // ...

}

 

제너레이터(Generator)

 

일련의 값을 느리게 생성하는 경우 제너레이터 함수를 사용하는 방법도 있습니다. Dart는 두 종류의 제너레이터 기능을  지원합니다.

  • Synchronous(동기) 제너레이터: Iterable 객체를 반환
  • Asynchronous(비동기) 제너레이터: Stream 객체를 반환

동기 생성기 함수를 구현하려면 함수 본문을 sync *로 표시하고 yield 문으로 값을 돌려줍니다.

 

Iterable<int> naturalsTo(int n) sync* {

  int k = 0;

  while (k < n)

    yield k++;

}

 

비동기 생성기 함수를 구현하려면 함수 본문을 async *로 표시하고 yield 문으로 값을 돌려줍니다.

 

Stream<int> asynchronousNaturalsTo(int n) async* {

  int k = 0;

  while (k < n)

    yield k++;

}

 

제너레이터가 재귀호출 구조이면 yield *를 사용하여 성능을 향상시킬 수 있습니다.

 

Iterable<int> naturalsDownFrom(int n) sync* {

  if (n > 0) {

    yield n;

    yield* naturalsDownFrom(n - 1);

  }

}

 

<이상>

 

반응형

'Dart' 카테고리의 다른 글

Dart, 자료형 별명 사용 (typedef)  (0) 2021.06.17
Dart, 호출 가능 클래스 (Callable classes)  (0) 2021.06.17
Dart, 라이브러리와 가시성  (0) 2021.06.17
Dart, 제너릭(Generic)  (0) 2021.06.17
Dart, 클래스 변수와 메서드  (0) 2021.06.17

+ Recent posts