[C#] 기다리다 Task.Wait-교착 상태?

꽤 차이 이해가 안 Task.Waitawait.

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않습니까?



답변

Waitawait– 개념적으로 유사한 동안 – 사실은 완전히 다릅니다.

Wait작업이 완료 될 때까지 동 기적으로 차단합니다. 따라서 현재 스레드는 작업이 완료되기를 기다리는 그대로 문자 그대로 차단됩니다. 일반적으로 “완료”를 사용해야합니다 async. 즉, async코드를 차단하지 마십시오 . 내 블로그 에서 비동기 코드 차단이 교착 상태를 일으키는 방법 에 대한 세부 정보를 살펴 봅니다 .

await작업이 완료 될 때까지 비동기 적으로 기다립니다. 이는 현재 메소드 가 “일시 중지됨”(상태가 캡처 됨)이며 메소드가 불완전한 태스크를 호출자에게 리턴 함을 의미합니다. 나중에 await식이 완료되면 나머지 메서드는 연속으로 예약됩니다.

또한 “협업 블록”을 언급했는데, 여기서는 현재 작업중인 작업이 Wait대기 스레드에서 실행될 수 있다고 가정합니다 . 이런 상황이 발생할 수 있지만 최적화입니다. 작업이 다른 스케줄러 용이거나 이미 시작되었거나 코드가 아닌 작업 인 경우와 같이 (예 : 코드 가 없으므로 인라인으로 작업을 실행할 수없는 경우) 발생할 수없는 상황이 많이 있습니다 . 그것을 위해).WaitDelay

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

내 영어 죄송합니다.


답변