비동기

허준호·2025년 6월 27일
0

dart 언어 공부

목록 보기
11/16
post-thumbnail

동기(Synchronous) 프로그래밍

동기란 ‘동시에 일어난다’라는 뜻이다

특징

  • 코드가 순서대로 실행된다
  • 이전 작업이 끝나야 다음 작업이 시작된다
  • 작업이 완료될 때까지 프로그램이 중단될 수 없다

장점

코드의 실행 순서가 예측 가능하다


비동기(Asynchronous) 프로그래밍

비동기란 ‘동시에 일어나지 않는다’라는 뜻이다

특징

  • 여러 작업이 병렬로 실행될 수 있다
  • 한 작업의 완료여부 상관없이 다음 작업이 실행될 수 있다

장점

I/O 작업이나 네트워크 요청같이 시간이 오래걸리는 작업에 유용하다

단점

작업의 완료 순서를 예측할 수 없다


동시성 vs. 병렬성

여러 작업을 처리하는 방식에 대한 차이이다

동시성(Concurrency)

여러 작업을 번갈아가면서 처리하는 것

  • 여러 작업이 논리적으로 동시에 처리되는 것처럼 보이는 개념이다
  • 시분할 방식으로 여러 스레드를 활용해 동시성을 구현할 수 있다

병렬성

여러 작업을 실제로 동시에 처리하는 것

  • 여러 작업이 물리적으로 동시에 실행되는 개념이다
  • 멀티코어 환경에서 실제로 여러 스레드가 병렬로 실행될 수 있다

정리

  1. 하나의 교사가 여러가지 일을 하는 것 (싱글 코어) ⇒ 동시성
  2. 교사와 조교가 함께 일을 하는 것 (멀티 코어) ⇒ 병렬성
  3. 순서대로 실행하는 것 ⇒ 동기
  4. 동시에 실행하는 것 ⇒ 비동기 (동시성, 병렬성을 모두 표현할 수 있음)

비동기 방식

1. 콜백 함수

파라미터로 함수를 받는 함수이다

단점

여러 개의 중첩된 콜백을 처리할 때 코드 가독성과 유지 관리성이 저하되어 "콜백 지옥" 또는 "파멸의 피라미드"라는 현상이 발생할 수 있다.

2. Future와 then 사용

동시에 여러가지 비동기 함수를 실행할 수 있다

fetchFirstData()
  .then((firstResult) {
    print("첫 번째 데이터: $firstResult");
    return fetchSecondData(firstResult);  // 두 번째 Future 반환
  })
  .then((secondResult) {
    print("두 번째 데이터: $secondResult");
    return "처리 완료";  // 일반 값 반환 (자동으로 Future로 변환됨)
  })
  .then((finalResult) {
    print("최종 결과: $finalResult");
  });

단점

  • 실행 순서나 완료의 예측이 어려움
  • 로직이 복잡해지면 적절한 예외처리하기에 용이하지 않다
Future<String> fetchData(String id, int delay) {
  return Future.delayed(Duration(seconds: delay), () {
    print('${DateTime.now().toString().substring(0, 19)}: 데이터 $id 완료');
    return '데이터 $id';
  });
}

void main() {
  print('${DateTime.now().toString().substring(0, 19)}: 시작');

  // 세 개의 비동기 작업을 동시에 시작
  // 지연 시간이 다르지만 실행 순서는 예측 불가능
  fetchData('A', 2).then((data) => print('결과 A: $data'));
  fetchData('B', 1).then((data) => print('결과 B: $data'));
  fetchData('C', 3).then((data) => print('결과 C: $data'));

  print('${DateTime.now().toString().substring(0, 19)}: 모든 작업 시작됨');
}

3. async/await 사용

  • 비동기 코드를 순차 실행되도록 한다 ⇒ 디버깅이 쉽다. 예측이 가능하다
  • await 키워드는 async 키워드가 있는 함수에서만 사용할 수 있다
  • 반환타입이 Future인 함수에 async 키워드가 반드시 있어야 하는것은 아니다
  • 성능은 떨어질 수 있다
Future<String> fetchData() async {
	await Future.delayed(Duration(seconds: 1));
	return '데이터';
}

void main() async {
	String data = await fetchData();
	print(data);
}

예외처리 방식

Future 클래스에 catchError라는 메소드가 있지만, try-catch문을 사용하는 것을 추천

Future<String> getData() async {
	try {
		// 데이터를 가져우는 비동기 작업
		var data = await _getDataFromAPI();
		return data;
	} catch (error) {
		// 데이터를 가져오는 데 실패했을 때 처리
		print('데이터를 가져오는 데 실패했습니다: $error');
		return '';
	}
}

병렬 처리

Future.wait은 모든 처리가 끝날 때까지 기다린다

장점

병렬 프로그래밍은 성능 향상의 장점이 있다

단점

  • 복잡도가 증가한다
  • 동기화가 필요하다
  • 디버깅이 어렵다
profile
후추랑 소금 좋아하는 개발자

0개의 댓글