C# Await 사용에 관한 질문 (Async Method & Task.Run)

안녕하세요 :smile:
Await를 사용하기 위한 비동기 메서드(async)와 Task.Run() 호출 방식에 대한 질문을 드리고자 합니다.

저는 두 가지 방식 모두 사용하고 있습니다. 하지만 정확히 두 방식간에 어떤 차이점이 있는지, 또는 문법적으로만 다른 것일 뿐인지도 궁금합니다.

아래는 await를 통해 화면을 비동기 처럼 갱신해주는 작업입니다.

메서드를 비동기 처럼 변경 (async void)

btn.Click += Btn_Click;

private async void Btn_Click()
{
    await CreateButtons(); 
}

private async Task GetUsersAsync()
{
    for (int i = 0; i < 100; i++)
    {
        await Task.Delay(1);
        this.Dispatcher.Invoke(()=> 
        { 
            stack.Children.Add(new Button { Content = i.ToString() }); 
        });
    }
}

메서드 안에 Task.Run() 호출

private oid Btn_Click()
{
    Task.Run(async () => { await CreateButtons(); });    
}

WPF 관련 개발을 하면서 자주 await를 사용하게 되는데요. 비동기, Thread 같은 처리에 대해 아직 부족함이 많아 깊이 있게 접근하지 못한체로 막연하게 쓰고 있는 부분이 많습니다.

읽어주셔서 감사합니다.!

좋아요 1

위에꺼는 스레드 한 번. 밑에꺼는 스레드 두 번의 차이만 있는 듯 합니다. 아시겠지만 TAP방식의 async await키워드를 사용한 다는 것은 스레드풀을 이용한다는 것입니다. async메서드는 il를 까보면 일반 메서드랑은 많이 다른 여러 키워드가 붙습니다.(async가 그걸 간단하게 해주지만요) async메서드를 호출시 스레드 풀에서 하나 받아서 await에서 반환되는 시점에 스레드가 사용완료되며 스래드 풀에 반환이 되는 것으로 알고 있습니다.

createbuttons 메서드가 이름으로 봐서는 버튼을 만들어내는 메서드로 추측이 되는데 버튼을 만드는 것은 ui 작업에 해당하므로 디스페처동기화를 사용하셨을 거로 예상이 되네요.

따라서 1번 방식은

  1. ui스레드에서 비동기 버튼 이벤트 발생
  2. 스레드풀에서 createbuttons 메서드로 스레드 할당 후 작업
  3. 스레드 내부에서 dispatcher 및 를synchoronizationcontext 통한 워커 스레드와 ui스레드의 동기화
  4. 작업 완료 후 스레드를 스레드 풀에 반환 후 await 시점에 워커스레드와 ui스레드의 동기화(1번 순서에 대한 동기화)

로 추측이 됩니다.

2번 방식은

  1. 동기형식의 이벤트 발생
  2. 워커스레드를 호출 하지만 await을 통해 대기를 하지는 않음. (대기를 하지 않을 뿐 완료되면 자동 반환)
  3. 워커스레드에서 비동기 메서드를 호출
  4. ‘다른’ 워커스레드를 받아서 createbuttons 메서드를 비동기적으로 호출
  5. 내부에서 dispatcher와 synchoronizationcontext 를 통해 ui스레드와 워커스레드의 동기화
  6. 동기화 후 ‘다른’ 워커스레드에 await을 통해 작업 반환 후 스레드 반환
  7. ‘다른’ 워커스레드의 작업 완료 후 스레드 반환하지만 await이 없어서 task.run 을 대기하지는 않음.

순서가 될 것 같습니다.
아…그리고 질문 논외지만 비동기 메서드이름에는 일반적으로 메서드 뒤에 Async가 붙으니 적어주신다면 헷갈리지 않을 듯 합니다.

혹 제가 틀린 부분이 있다면 꼭 지적 부탁 드립니다.
감사합니다.

좋아요 3

@Vincent 상세한 설명 정말 감사합니다!! (감동) :smile:
논외로 말씀해주신 Async 규칙도 알려주셔서 감사합니다.

좋아요 1