첫째, Servy는 비슷한 질문에 대한 답변으로 몇 가지 코드를 작성했습니다.
/programming/22049339/how-to-create-a-cancellable-task-loop
Servy의 답변에는 and 및 키워드를 ContinueWith()
명시 적으로 사용하지 않고 TPL 구문을 사용 하는 유사한 루프가 포함됩니다 . 질문에 대답하기 위해 루프를 풀 때 코드가 어떻게 보일지 고려하십시오.async
await
ContinueWith()
private static Task GetWorkWhileNotQuit()
{
var tcs = new TaskCompletionSource<bool>();
Task previous = Task.FromResult(_quit);
Action<Task> continuation = null;
continuation = t =>
{
if (!_quit)
{
previous = previous.ContinueWith(_ => GetWorkAsync())
.Unwrap()
.ContinueWith(_ => previous.ContinueWith(continuation));
}
else
{
tcs.SetResult(_quit);
}
};
previous.ContinueWith(continuation);
return tcs.Task;
}
머리를 감싸는 데 시간이 걸리지 만 요약하면 다음과 같습니다.
continuation
"현재 반복"에 대한 폐쇄를 나타냅니다.
previous
"이전 반복"Task
의 상태를 포함 함을 나타냅니다 (즉, '반복'이 완료된시기를 알고 다음 반복을 시작하는 데 사용됨).
- 를
GetWorkAsync()
반환 한다고 가정하면 '내부 작업'(즉, 실제 결과 ) 을 얻기위한 호출을 반환 Task
한다는 의미 ContinueWith(_ => GetWorkAsync())
입니다 .Task<Task>
Unwrap()
GetWorkAsync()
그래서:
- 처음에는 이전 반복 이 없으므로 단순히 값이 할당
Task.FromResult(_quit)
됩니다 Task.Completed == true
. 상태는로 시작됩니다 .
- 를
continuation
사용하여 처음으로 실행previous.ContinueWith(continuation)
- 완료 상태를 반영 하여
continuation
클로저 업데이트previous
_ => GetWorkAsync()
- 때
_ => GetWorkAsync()
완료, 그것은 "계속" _previous.ContinueWith(continuation)
- 즉, 호출 continuation
을 다시 람다
- 분명히이 시점
previous
에서 상태로 업데이트 _ => GetWorkAsync()
되었으므로 continuation
람다는 GetWorkAsync()
반환 할 때 호출됩니다 .
continuation
람다는 항상의 상태를 확인 _quit
하는 경우, 정도 _quit == false
후 더 이상 연속성을가없고,이 TaskCompletionSource
값으로 설정됩니다 _quit
, 모든 것이 완료됩니다.
다른 스레드에서 실행되는 연속성에 대한 귀하의 관찰에 관해서는 이 블로그에서 "태스크는 여전히 스레드가 아니며 비동기는 병렬이 아닙니다"와 같이 async
/ await
키워드가 당신을 위해 할 일 이 아닙니다 . -https : //blogs.msdn.microsoft.com/benwilli/2015/09/10/tasks-are-still-not-threads-and-async-is-not-parallel/
GetWorkAsync()
스레딩 및 스레드 안전성과 관련하여 귀하의 방법을 자세히 살펴볼 가치가 있다고 제안합니다 . 진단에서 반복 된 비동기 / 대기 코드의 결과로 다른 스레드에서 실행 중임을 표시하는 경우 해당 메소드 내부 또는 관련 메소드로 인해 다른 스레드에서 새 스레드가 작성되어야합니다. (이것이 예기치 않은 경우 .ConfigureAwait
어딘가에 있습니까?)