async await Behavior [중복]
나는 async-await로 실험하고 있었고 적어도 나에게는 다소 이상한 행동을 보았습니다.
장기 실행 작업을 시뮬레이션하는 세 가지 방법을 만들었습니다.
두 개의 버튼 클릭 핸들러를 고려하십시오.
button1_click의 경우 경과 시간은 약 6000ms 였고 button2_click은 약 3000ms였습니다.
나는 이것이 왜 일어 났는지, 즉 6000ms 대 3000ms에 대해 내 머리를 감쌀 수 없습니다.
private async Task<string> TaskOne()
{
await Task.Delay(1000);
return "task one";
}
private async Task<string> TaskTwo()
{
await Task.Delay(2000);
return "task two";
}
private async Task<string> TaskThree()
{
await Task.Delay(3000);
return "task three";
}
//time elapsed = 6000+ms
private async void button1_Click(object sender, EventArgs e)
{
var watch = new Stopwatch();
watch.Start();
await TaskOne();
await TaskTwo();
await TaskThree();
watch.Stop();
textBox3.Text = watch.ElapsedMilliseconds.ToString();
}
//time elapsed = 3000+ms
private async void button2_Click(object sender, EventArgs e)
{
var watch = new Stopwatch();
watch.Start();
var taskOne = TaskOne();
var taskTwo = TaskTwo();
var taskThree = TaskThree();
await taskOne;
await taskTwo;
await taskThree;
watch.Stop();
textBox3.Text = watch.ElapsedMilliseconds.ToString();
}
답변
이 경우 :
await TaskOne();
await TaskTwo();
await TaskThree();
TaskTwo ()는 대기 중이므로 TaskOne ()이 완료 될 때까지 시작할 수 없습니다. 마찬가지로 TaskThree ()는 await 때문에 TaskTwo ()가 완료 될 때까지 시작할 수 없습니다.
다음에:
var taskOne = TaskOne();
var taskTwo = TaskTwo();
var taskThree = TaskThree();
await taskOne;
await taskTwo;
await taskThree;
3 개의 작업을 동시에 시작하고 기다리고 있습니다. 이것이 가장 오래 실행되는 작업만큼만 오래 걸리는 이유입니다. 얼마나 많은 사람들이 비동기 대기에 대해 이것을 이해하지 못하는지 놀라실 것입니다. 작업이 서로 의존하지 않는다면 이것이 갈 길입니다.
요약
여기서 집으로 가져가는 요점은 (그렇지 않으면 매우 일반적인 오해입니다) await
실제로 "기다리다"를 의미 합니다.
await 연산자 (C # 참조)
내 강조
await 연산자는 피연산자가 나타내는 비동기 연산이 완료 될 때까지 둘러싸는 비동기 메서드의 평가를 일시 중단 합니다. 비동기 작업이 완료되면 await 연산자가 작업 결과를 반환합니다 (있는 경우).
이미 완료된 작업을 나타내는 피연산자에 await 연산자를 적용하면 둘러싸는 메서드를 중단하지 않고 즉시 작업 결과를 반환합니다 .
await 연산자는 비동기 메서드를 평가하는 스레드를 차단하지 않습니다. await 연산자가 바깥 쪽 비동기 메서드를 일시 중단하면 컨트롤이 메서드 호출자에게 반환됩니다.
그래서 여기에 무슨 일이 일어나고 있는지입니다. 첫 번째 예에서는 각 작업을 시작하고 연속적으로 완료되기를 기다리고 있습니다. 즉, 다음 사람에게 무언가를 요청하기 전에 누군가에게 가서 무언가를하고 끝내라고 요청하는 것과 같습니다.
await TaskOne(); // start, do something and wait for it
await TaskTwo(); // start, do something and wait for it
await TaskThree(); // start, do something and wait for it
두 번째 예. 기본적으로 3 가지 작업 (핫)을 시작한 다음 한 번에 하나씩 완료되기를 기다립니다. 즉, 동시에 실행되고 순서대로 대기했습니다.
즉, 당신은 3 명의 친구에게 말하고, 가서 일을하고, 첫 번째가 돌아올 때까지 기다렸다가 두 번째, 세 번째를 기다리십시오. 훨씬 더 효율적입니다 ... 이전 친구가 돌아올 때까지 성가신 친구가 없습니다.
짝수 경우 두 번째 작업의 완료가되기 전에 첫째 , 당신은 여전히 유효하다 기다리는 첫 번째 작업 상기보기 전에 완료 상태 의 두 번째 작업 등
var taskOne = TaskOne(); // start, do something
var taskTwo = TaskTwo(); // start, do something
var taskThree = TaskThree(); // start, do something
// all 3 tasks are started
await taskOne; // wait for it
await taskTwo; // wait for it
await taskThree; // wait for it
또는 비슷하게 사용할 수 있습니다. Task.WhenAll
제공된 모든 작업이 완료되면 완료 될 작업을 만듭니다.
var taskOne = TaskOne(); // start, do something
var taskTwo = TaskTwo(); // start, do something
var taskThree = TaskThree(); // start, do something
// wait for them all to finish!
await Task.WhenAll(taskOne, taskTwo, taskThree);