누군가 설명 할 수있는 경우await과ContinueWith다음 예제에서는 동의어 또는 동일하지 않습니다. 나는 TPL을 처음 사용하려고 노력하고 있으며 모든 문서를 읽었지만 그 차이를 이해하지 못합니다.
기다리다:
String webText = await getWebPage(uri);
await parseData(webText);
계속하십시오:
Task<String> webText = new Task<String>(() => getWebPage(uri));
Task continue = webText.ContinueWith((task) =>  parseData(task.Result));
webText.Start();
continue.Wait();
특정 상황에서 다른 것보다 하나가 선호됩니까?
두 번째 코드에서는동 기적으로지속이 끝나기를 기다린다. 첫 번째 버전에서는 메서드가 첫 번째 버전과 충돌하는 즉시 호출자에게 반환됩니다.await아직 완료되지 않은 표현.
그들은 둘 다 계속 일정을 잡는다는 점에서 매우 유사하지만, 제어 흐름이 약간 복잡해 지 자마자,await~으로 이끌다많은더 간단한 코드. 또한 Servy가 주석에서 언급했듯이 작업을 기다리는 것은 일반적으로 간단한 오류 처리로 이어지는 집계 예외를 "해제"합니다. 또한 사용await호출 컨텍스트에서 연속을 암시 적으로 예약합니다 (사용하지 않는 한).ConfigureAwait). "수동으로"수행 할 수없는 것은 아니지만,await.
둘 다 약간 더 큰 작업 순서를 구현하는 것이 좋습니다.await과Task.ContinueWith- 진짜 눈을 뜨게 될 수 있습니다.
await위에ContinueWith그 점에서. - ServyparseData에서 실행됩니다. - Stephen Cleary
비동기 해결을 사용하여 차이점과 다양한 문제를 설명하기 위해 최근에 사용한 코드 스 니펫 시퀀스가 있습니다.
GUI 기반 애플리케이션에 시간이 많이 소요되는 이벤트 핸들러가 있고이를 비동기로 만들고 싶다고 가정 해 보겠습니다. 다음은 함께 시작하는 동기식 로직입니다.
while (true) {
    string result = LoadNextItem().Result;
    if (result.Contains("target")) {
        Counter.Value = result.Length;
        break;
    }
}
LoadNextItem은 검사 할 결과를 결국 생성하는 Task를 반환합니다. 현재 결과가 원하는 결과라면 UI의 일부 카운터 값을 업데이트하고 메서드에서 돌아옵니다. 그렇지 않으면 LoadNextItem에서 더 많은 항목을 계속 처리합니다.
비동기 버전에 대한 첫 번째 아이디어는 계속 사용하십시오! 그리고 당분간 반복되는 부분을 무시해 봅시다. 무슨 일이 생길 수 있니?
return LoadNextItem().ContinueWith(t => {
    string result = t.Result;
    if (result.Contains("target")) {
        Counter.Value = result.Length;
    }
});
좋아요, 이제 차단하지 않는 방법이 있습니다! 대신 충돌이 발생합니다. UI 컨트롤에 대한 업데이트는 UI 스레드에서 발생하므로이를 고려해야합니다. 고맙게도 연속성을 예약하는 방법을 지정하는 옵션이 있습니다.이 옵션에는 기본 설정이 있습니다.
return LoadNextItem().ContinueWith(t => {
    string result = t.Result;
    if (result.Contains("target")) {
        Counter.Value = result.Length;
    }
},
TaskScheduler.FromCurrentSynchronizationContext());
좋아, 이제 우리는 충돌하지 않는 방법을 가지고있다! 대신 자동으로 실패합니다. 연속은 별도의 작업으로, 그 상태는 이전 작업의 상태와 관련이 없습니다. 따라서 LoadNextItem이 실패하더라도 호출자는 성공적으로 완료된 태스크 만 볼 수 있습니다. 좋아요, 그렇다면 예외를 넘겨주세요.
return LoadNextItem().ContinueWith(t => {
    if (t.Exception != null) {
        throw t.Exception.InnerException;
    }
    string result = t.Result;
    if (result.Contains("target")) {
        Counter.Value = result.Length;
    }
},
TaskScheduler.FromCurrentSynchronizationContext());
좋습니다. 이제 실제로 작동합니다. 단일 품목의 경우. 자, 그 루핑은 어때? 사실, 원래 동기식 버전의 로직과 같은 솔루션은 다음과 같이 보일 것입니다.
Task AsyncLoop() {
    return AsyncLoopTask().ContinueWith(t =>
        Counter.Value = t.Result,
        TaskScheduler.FromCurrentSynchronizationContext());
}
Task<int> AsyncLoopTask() {
    var tcs = new TaskCompletionSource<int>();
    DoIteration(tcs);
    return tcs.Task;
}
void DoIteration(TaskCompletionSource<int> tcs) {
    LoadNextItem().ContinueWith(t => {
        if (t.Exception != null) {
            tcs.TrySetException(t.Exception.InnerException);
        } else if (t.Result.Contains("target")) {
            tcs.TrySetResult(t.Result.Length);
        } else {
            DoIteration(tcs);
        }});
}
또는 위의 모든 것 대신 async를 사용하여 동일한 작업을 수행 할 수 있습니다.
async Task AsyncLoop() {
    while (true) {
        string result = await LoadNextItem();
        if (result.Contains("target")) {
            Counter.Value = result.Length;
            break;
        }
    }
}
지금은 훨씬 좋네요, 그렇죠?
Wait두 번째 예제에서 호출그때두 개의 미리보기는 (대부분) 동등한 것입니다. - ServygetWebPage메소드를 두 코드 모두에서 사용할 수 없습니다. 첫 번째 코드에는Task<string>반환 유형은 두 번째로string리턴 유형. 기본적으로 코드는 컴파일되지 않습니다. - 정확하면. - Royi Namir