기다리다 Task.Wait-교착 상태?


197

꽤 차이 이해가 안 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않습니까?


@ Servy : 시간이 되 자마자 repo와 함께 돌아올 것입니다. 지금 Task.Delay(1).Wait()은 충분히 작동합니다 .
ronag

2
Task.Delay(1).Wait()기본적으로와 정확히 같은 것 Thread.Sleep(1000)입니다. 실제 생산 코드에서는 거의 적합하지 않습니다.
Servy

@ronag : WaitAll교착 상태가 발생했습니다. 자세한 내용은 답변에서 내 블로그 링크를 참조하십시오. await Task.WhenAll대신 사용해야 합니다.
Stephen Cleary

6
@ronag 교착 상태에 ConfigureAwait(false)대한 단일 호출이 Bar있거나 Ros교착 상태가 발생하지 않지만 열거 형이 하나 이상 생성 된 다음 모든 항목을 기다리고 있기 때문에 첫 번째 막대는 두 번째 교착 상태를 교착 상태로 만듭니다. 당신이 경우 await Task.WhenAll대신 당신이 ASP 컨텍스트를 차단하지 그래서, 모든 작업을 기다리고, 당신은 방법의 반환을 정상적으로 볼 수 있습니다.
Servy

2
@ronag 귀하의 다른 옵션을 추가하는 것입니다 .ConfigureAwait(false) 트리까지 모든 방법을 당신이 그런 식으로 아무것도입니다 차단 될 때까지 지금 다시 주요 문맥을 얻으려고 노력하지; 작동합니다. 또 다른 옵션은 내부 동기화 컨텍스트를 스핀 업하는 것입니다. 링크 . 당신이를 넣으면 Task.WhenAllAsyncPump.Run효과적으로 당신이 필요없이 모든 일에 차단 ConfigureAwait어디서나, 그러나 아마 지나치게 복잡한 해결책이.
Servy

답변:


270

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

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

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

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

async/ await소개가 도움 이 될 수 있습니다.


5
나는 오해가 있다고 생각하고 Wait훌륭한 await교착 상태를 작동 시킵니다 .
ronag

1
분명히 : 내 대체하는 경우 예 await Task.Delay(1)Task.Delay(1).Wait()서비스 그렇지 않으면 교착, 잘 작동합니다.
ronag

5
아니오, 작업 스케줄러는 그렇게하지 않습니다. Wait스레드를 차단하고 다른 용도로는 사용할 수 없습니다.
Stephen Cleary

8
@ronag 내 생각에 방금 메서드 이름이 섞여 있고 교착 상태가 실제로 차단 코드로 인해 코드로 작동했습니다 await. 또는 교착 상태가 둘 중 하나와 관련이 없으며 문제를 잘못 진단했습니다.
Servy

3
@ hexterminator : 이것은 의도적으로 설계된 것입니다 .UI 앱에는 효과적이지만 ASP.NET 앱에는 방해가되는 경향이 있습니다. ASP.NET Core는을 제거하여이 문제를 해결 SynchronizationContext했으므로 ASP.NET Core 요청 내에서 차단하면 더 이상 교착 상태가 발생하지 않습니다.
Stephen Cleary

5

다른 출처에서 읽은 내용을 기반으로합니다.

await표현은 실행중인 스레드를 차단하지 않는다. 대신, 컴파일러가 나머지 async메소드를 대기중인 태스크의 연속으로 등록하게합니다. 그런 다음 제어는 async메소드 의 호출자에게 리턴합니다 . 작업이 완료되면 작업이 계속 진행되고 async중단 된 지점 에서 메소드 실행이 재개됩니다.

싱글 task이 완료 되기를 기다리려면 Task.Wait메소드를 호출하면 됩니다. 받는 호출 Wait단일 클래스 인스턴스까지 메소드는 블록 호출 스레드가 실행을 완료했습니다. 매개 변수가없는 Wait()방법은 작업이 완료 될 때까지 무조건 대기하는 데 사용됩니다. 이 작업 Thread.Sleep은 2 초 동안 휴면 모드를 호출하여 작업을 시뮬레이션합니다 .

이 기사 도 잘 읽었습니다.


3
"그런게 기술적으로 틀리지 않습니까? 다른 사람이 명확하게 설명해 주시겠습니까?" -명확히 할 수 있습니까? 질문으로 그 질문을합니까? (단지 당신이 묻는 지 대답하고 있는지 명확하게하고 싶습니다). 당신이 묻는다면 : 그것은 별도의 질문으로 더 잘 작동 할 수 있습니다. 답변으로 여기에 새로운 답변을 수집 할 것 같지 않습니다
Marc Gravell

1
나는 질문에 대답하고 여기에있는 의심에 대해 별도의 질문을했다 stackoverflow.com/questions/53654006/… 감사합니다 @MarcGravell. 답변에 대한 삭제 투표를 제거 할 수 있습니까?
Ayushmati

"지금 답변에 대한 삭제 투표를 제거 할 수 있습니까?" -그건 내 것이 아니다. ♦ 덕분에 본인의 투표는 즉시 효력을 발휘했을 것입니다. 그러나 이것이 교착 상태 행동에 관한 질문의 핵심 포인트에 대한 답변이라고 생각하지 않습니다.
Marc Gravell

사실이 아닙니다. 처음 기다릴 때까지 모든 것이 차단됩니다
user1785960

-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

내 영어 죄송합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.