[Unity]/[C#]

[C#] 비동기 메서드(async, await)

극꼼 2022. 9. 21. 21:39
반응형


<비동기 메서드 선언 방법>

: async 키워드를 사용하며, 매개 변수에 out, ref같은 한정자는 사용할 수 없습니다.(일부 비동기 메서드는 호출 측으로 반환되지 않아서 참조를 통한 매개변수 전달을 허용하지 않음)

static void Main(string[] args)
{
    Task task = DemoCompletedAsync(); // -> 비동기 메서드 호출
    Console.WriteLine("Method return");
    task.Wait(); // -> 작업이 완료될 때까지 중단
    Console.WriteLine("Task completed");
}
static async Task DemoCompletedAsync()
{
    Console.WriteLine("first await start : ");
    await Task.FromResult(10); // -> 완료된 작업을 대기
    Console.WriteLine("second await start : ");
    await Task.FromResult(1000); // -> 완료되지 않은 작업을 대기
    Console.WriteLine("second await finish");
}

 

출력은 다음과 같습니다.

first await start : 
second await start : 
Method return //두번째 await가 완료되지 않았지만 일단 메서드 반환
second await finish 
Task completed //메서드 완료

<await>

* 주요 목적 : 시간을 많이 소비하는 작업이 완료될 때까지 수행이 중단되는 것을 막는 것.

* await 연산자 사용 : 대기 가능한 객체에 대해서만 사용할 수 있습니다.

* 연산자의 우선순위 : 

int result = await foo.Bar().Baz();
//await 연산자의 우선순위는 점 연산자보다 낮음 -> 아래 코드처럼 작동.
int result = await (foo.Bar().Baz());
//foo.Bar() -> Baz() -> await 순서로 동작.

 


<비동기 메서드의 흐름>

* continuation : 비동기 작업이 완료되었을 때 수행할 콜백. 메서드의 수행 상태를 저장하는 용도로 사용되며, 현재의 수행 위치를 관리합니다.

* 비동기 작업 대기 동안 메서드가 일시 중단 상태로 보이는데, 컴파일러는 continuation을 수행할 때까지 메서드 내에서 사용하는 모든 지역변수의 값을 온전하게 유지할 수 있게 코드를 생성해줍니다. 

* 비동기적 대기 = 메서드가 실제로 전혀 실행되지 않음 → 비동기 작업에 컨티뉴에이션을 결합한 후 메서드가 반환 → 비동기를 구현한 내부 구현부에서 컨티뉴에이션이 적절한 스레드를 통해 수행될 수 있도록 해줌. 

 

* 비동기 메서드의 반환 시점과 완료 시점은 다릅니다.

  • 반환 시점 : 메서드의 호출 측으로 반환되거나 결합된 컨티뉴에이션을 수행하는 것.
  • 완료 시점 : 컨티뉴에이션을 끝냄.

* 너무 오래 수행되는 블로킹 작업은 별도의 메서드로 분리하고 별도의 Task를 생성하는게 좋습니다.

 

* 비동기 메서드의 흐름 :

1) await 표현식에 도달 = continuation을 비동기 작업에 결합.

2) void 메서드는 즉시 반환, 비동기 메서드는 작업을 나타내는 객체를 반환.

3) 내부에서 continuation이 적절한 스레드를 통해 수행될 수 있도록 해줌.

4) 비동기 작업이 완료 -> 메서드의 나머지 코드를 읽음.

  - Task 객체는 비동기 작업이 언제 어떻게 완료되는지를 나타내줌(Status = RanToCompletion, Result = 수행 결과값)

  - Task의 상태가 완결 상태로 바뀌면, 연관된 컨티뉴에이션(대기하던 또 다른 비동기 메서드) 수행을 위해 스케줄링.

 


<활용 팁>

  • ConfigureAwait로 컨텍스트를 저장하는 것은 피하기.
    • ConfigureAwait(false) 호출 결과 : 이전 동기화 컨텍스트를 고려할 필요 없이 독립적으로 스케줄링 가능한 컨티뉴에이션을 반환. 이 컨티뉴에이션은 스레드 풀 내의 다른 스레드에 의해 수행될 수 있음.
  • 여러 작업이 독립적으로 수행될 수 있게 작성하고 이를 병렬적으로 수행.
  • 동기 코드와 비동기 코드를 섞어 쓰지 않기
  • 취소가 가능하게 코드를 작성하기
  • 비동기성을 테스트하기
반응형

'[Unity] > [C#]' 카테고리의 다른 글

[C#] Tuple(튜플) 형식  (0) 2022.09.27
[C#] Action과 Func  (0) 2022.09.26
[C#] ConditionalAttribute  (0) 2022.09.20
[C#] MethodImpl (feat.인라인 함수)  (0) 2022.09.19
[C#] internal 액세스 한정자  (0) 2022.09.18