[C#] 기다리다 Task.Wait-교착 상태?
꽤 차이 이해가 안 Task.Wait
와 await
.
ASP.NET WebAPI 서비스에 다음 기능과 비슷한 것이 있습니다.
public class TestController : ApiController
{
public static async Task<string> Foo()
{
await Task.Delay(1).ConfigureAwait(false);
return "";
}
public async static Task<string> Bar()
{
return await Foo();
}
public async static Task<string> Ros()
{
return await Bar();
}
// GET api/test
public IEnumerable<string> Get()
{
Task.WaitAll(Enumerable.Range(0, 10).Select(x => Ros()).ToArray());
return new string[] { "value1", "value2" }; // This will never execute
}
}
Get
교착 상태는 어디 입니까?
무엇이 이것을 일으킬 수 있습니까? 차단 대기 시간을 사용할 때 왜 이것이 문제가되지 await Task.Delay
않습니까?
답변
Wait
와 await
– 개념적으로 유사한 동안 – 사실은 완전히 다릅니다.
Wait
작업이 완료 될 때까지 동 기적으로 차단합니다. 따라서 현재 스레드는 작업이 완료되기를 기다리는 그대로 문자 그대로 차단됩니다. 일반적으로 “완료”를 사용해야합니다 async
. 즉, async
코드를 차단하지 마십시오 . 내 블로그 에서 비동기 코드 차단이 교착 상태를 일으키는 방법 에 대한 세부 정보를 살펴 봅니다 .
await
작업이 완료 될 때까지 비동기 적으로 기다립니다. 이는 현재 메소드 가 “일시 중지됨”(상태가 캡처 됨)이며 메소드가 불완전한 태스크를 호출자에게 리턴 함을 의미합니다. 나중에 await
식이 완료되면 나머지 메서드는 연속으로 예약됩니다.
또한 “협업 블록”을 언급했는데, 여기서는 현재 작업중인 작업이 Wait
대기 스레드에서 실행될 수 있다고 가정합니다 . 이런 상황이 발생할 수 있지만 최적화입니다. 작업이 다른 스케줄러 용이거나 이미 시작되었거나 코드가 아닌 작업 인 경우와 같이 (예 : 코드 가 없으므로 인라인으로 작업을 실행할 수없는 경우) 발생할 수없는 상황이 많이 있습니다 . 그것을 위해).Wait
Delay
내 async
/ await
소개가 도움 이 될 수 있습니다.
답변
다른 출처에서 읽은 내용을 기반으로합니다.
await
표현은 실행중인 스레드를 차단하지 않는다. 대신, 컴파일러가 나머지 async
메소드를 대기중인 태스크의 연속으로 등록하게합니다. 그런 다음 제어는 async
메소드 의 호출자에게 리턴합니다 . 작업이 완료되면 작업이 계속 진행되고 async
중단 된 지점 에서 메소드 실행이 재개됩니다.
싱글 task
이 완료 되기를 기다리려면 Task.Wait
메소드를 호출하면 됩니다. 받는 호출 Wait
단일 클래스 인스턴스까지 메소드는 블록 호출 스레드가 실행을 완료했습니다. 매개 변수가없는 Wait()
방법은 작업이 완료 될 때까지 무조건 대기하는 데 사용됩니다. 이 작업 Thread.Sleep
은 2 초 동안 휴면 모드를 호출하여 작업을 시뮬레이션합니다 .
이 기사 도 잘 읽었습니다.
답변
다른 답변에는 몇 가지 중요한 사실이 제시되지 않았습니다.
“비동기 대기”는 CIL 수준에서 더 복잡하므로 메모리 및 CPU 시간이 걸립니다.
대기 시간이 허용되지 않으면 모든 작업을 취소 할 수 있습니다.
“async await”의 경우이를 취소하거나 모니터링 할 수있는 작업이 없습니다.
“비동기 대기”보다 작업을 사용하는 것이 더 유연합니다.
모든 동기화 기능은 비동기로 래핑 될 수 있습니다.
public async Task<ActionResult> DoAsync(long id)
{
return await Task.Run(() => { return DoSync(id); } );
}
“비동기 대기”는 많은 문제를 발생시킵니다. 우리는 이제 런타임 및 컨텍스트 디버깅없이 await 문에 도달하지 않습니다. 처음에 도달하지 않으면 모든 것이 차단 됩니다. 때로는 기다릴지라도 여전히 모든 것이 차단됩니다.
https://github.com/dotnet/runtime/issues/36063
동기화 및 비동기 방법이나 해킹을 사용하기 위해 코드 복제로 살아야하는 이유를 모르겠습니다.
결론 : 수동으로 작업을 생성하고 제어하는 것이 훨씬 좋습니다. 처리기 대 작업은 더 많은 제어를 제공합니다. 작업을 모니터링하고 관리 할 수 있습니다.
https://github.com/lsmolinski/MonitoredQueueBackgroundWorkItem
내 영어 죄송합니다.