[C#] Task.Start / Wait와 Async / Await의 차이점은 무엇입니까?

뭔가 빠졌을 수도 있지만 차이점은 무엇입니까?

public void MyMethod()
{
  Task t = Task.Factory.StartNew(DoSomethingThatTakesTime);
  t.Wait();
  UpdateLabelToSayItsComplete();
}

public async void MyMethod()
{
  var result = Task.Factory.StartNew(DoSomethingThatTakesTime);
  await result;
  UpdateLabelToSayItsComplete();
}

private void DoSomethingThatTakesTime()
{
  Thread.Sleep(10000);
}



답변

뭔가 빠졌을 수도 있습니다

너는.

Task.Wait과 의 차이점은 무엇 await task입니까?

식당에서 웨이터에게 점심을 주문합니다. 당신의 명령을 한 순간, 친구가 들어와 당신 옆에 앉아 대화를 시작합니다. 이제 두 가지 선택이 있습니다. 작업이 완료 될 때까지 친구를 무시할 수 있습니다. 수프가 도착할 때까지 기다렸다가 기다리는 동안 아무 것도 할 수 없습니다. 또는 친구에게 응답 할 수 있으며 친구가 말을 멈 추면 웨이터가 수프를 가져옵니다.

Task.Wait작업이 완료 될 때까지 차단-작업이 완료 될 때까지 친구를 무시합니다. await메시지 대기열에서 메시지 처리를 유지하고 작업이 완료되면 “대기 후 중단 한 부분을 선택합니다”라는 메시지를 대기열에 넣습니다. 친구와 대화를 나누고 대화가 중단되면 수프가 도착합니다.


답변

여기에 Eric의 대답을 보여주는 코드가 있습니다.

public void ButtonClick(object sender, EventArgs e)
{
  Task t = new Task.Factory.StartNew(DoSomethingThatTakesTime);
  t.Wait();
  //If you press Button2 now you won't see anything in the console 
  //until this task is complete and then the label will be updated!
  UpdateLabelToSayItsComplete();
}

public async void ButtonClick(object sender, EventArgs e)
{
  var result = Task.Factory.StartNew(DoSomethingThatTakesTime);
  await result;
  //If you press Button2 now you will see stuff in the console and 
  //when the long method returns it will update the label!
  UpdateLabelToSayItsComplete();
}

public void Button_2_Click(object sender, EventArgs e)
{
  Console.WriteLine("Button 2 Clicked");
}

private void DoSomethingThatTakesTime()
{
  Thread.Sleep(10000);
}


답변

이 예는 그 차이를 매우 명확하게 보여줍니다. async / await를 사용하면 호출 스레드가 차단되지 않고 계속 실행됩니다.

static void Main(string[] args)
{
    WriteOutput("Program Begin");
    // DoAsTask();
    DoAsAsync();
    WriteOutput("Program End");
    Console.ReadLine();
}

static void DoAsTask()
{
    WriteOutput("1 - Starting");
    var t = Task.Factory.StartNew<int>(DoSomethingThatTakesTime);
    WriteOutput("2 - Task started");
    t.Wait();
    WriteOutput("3 - Task completed with result: " + t.Result);
}

static async Task DoAsAsync()
{
    WriteOutput("1 - Starting");
    var t = Task.Factory.StartNew<int>(DoSomethingThatTakesTime);
    WriteOutput("2 - Task started");
    var result = await t;
    WriteOutput("3 - Task completed with result: " + result);
}

static int DoSomethingThatTakesTime()
{
    WriteOutput("A - Started something");
    Thread.Sleep(1000);
    WriteOutput("B - Completed something");
    return 123;
}

static void WriteOutput(string message)
{
    Console.WriteLine("[{0}] {1}", Thread.CurrentThread.ManagedThreadId, message);
}

DoAsTask 출력 :

[1] 프로그램 시작
[1] 1-시작
[1] 2-작업 시작
[3] A-시작한 것
[3] B-무언가를 완성 함
[1] 3-작업 완료 결과 : 123
[1] 프로그램 끝

DoAsAsync 출력 :

[1] 프로그램 시작
[1] 1-시작
[1] 2-작업 시작
[3] A-시작한 것
[1] 프로그램 끝
[3] B-무언가를 완성 함
[3] 3-작업 완료 결과 : 123

업데이트 : 출력에 스레드 ID를 표시하여 예제를 개선했습니다.


답변

Wait ()는 잠재적으로 비동기 코드를 동기화 방식으로 실행합니다. 기다리지 않습니다.

예를 들어 asp.net 웹 응용 프로그램이 있습니다. UserA는 / getUser / 1 엔드 포인트를 호출합니다. asp.net 앱 풀은 스레드 풀 (Thread1)에서 스레드를 선택하고이 스레드는 http 호출을 수행합니다. Wait ()를 수행하면 http 호출이 해결 될 때까지이 스레드가 차단됩니다. 기다리는 동안 UserB가 / getUser / 2를 호출하면 앱 풀은 다른 스레드 (Thread2)를 제공하여 http를 다시 호출해야합니다. Thread1을 사용할 수 없으므로 Wait ()에 의해 차단 되었기 때문에 방금 다른 스레드를 만들었습니다 (실제로 앱 풀에서 가져 왔습니다).

Thread1에서 await를 사용하면 SyncContext가 Thread1과 http 호출 간의 동기화를 관리합니다. 간단히 말하면 http 호출이 완료되면 알립니다. 한편 UserB가 / getUser / 2를 호출하면 Thread1을 다시 사용하여 http 호출이 이루어집니다. 그런 다음 다른 요청이 더 많은 것을 사용할 수 있습니다. http 호출이 완료되면 (user1 또는 user2) Thread1은 결과를 가져 와서 호출자 (클라이언트)에게 리턴 할 수 있습니다. Thread1은 여러 작업에 사용되었습니다.


답변

이 예에서는 실용적이지 않습니다. 다른 스레드 (예 : WCF 호출)를 반환하거나 파일 IO와 같은 운영 체제에 대한 제어 권한을 포기하는 작업을 기다리는 경우 대기는 스레드를 차단하지 않아 시스템 리소스를 덜 사용합니다.


답변

위의 예에서 “TaskCreationOptions.HideScheduler”를 사용하고 “DoAsTask”메소드를 크게 수정할 수 있습니다. “작업”값을 반환하고 “비동기”로 표시되어 여러 조합을 수행하기 때문에 “DoAsAsync”에서 발생하므로 메소드 자체는 비동기식이 아닙니다. “async / await”를 사용하는 것과 정확히 같은 방식입니다. :

static Task DoAsTask()
{
    WriteOutput("1 - Starting");
    var t = Task.Factory.StartNew<int>(DoSomethingThatTakesTime, TaskCreationOptions.HideScheduler); //<-- HideScheduler do the magic

    TaskCompletionSource<int> tsc = new TaskCompletionSource<int>();
    t.ContinueWith(tsk => tsc.TrySetResult(tsk.Result)); //<-- Set the result to the created Task

    WriteOutput("2 - Task started");

    tsc.Task.ContinueWith(tsk => WriteOutput("3 - Task completed with result: " + tsk.Result)); //<-- Complete the Task
    return tsc.Task;
}


답변