콘솔 응용 프로그램에서 여러 비동기 작업을 실행하고 추가 처리 전에 모두 완료 될 때까지 기다려야합니다.
많은 기사가 있지만 읽을수록 많이 혼란스러워하는 것 같습니다. 작업 라이브러리의 기본 원칙을 읽고 이해했지만 어딘가에 링크가 명확하게 없습니다.
나는 다른 완료 (시작한 모든 기사에 대한 시나리오 임) 후에 시작되도록 작업을 연결할 수 있지만 모든 작업이 동시에 실행되기를 원하며 한 번 알고 싶습니다. 그들은 모두 완료되었습니다.
이와 같은 시나리오의 가장 간단한 구현은 무엇입니까?
답변
두 답변 모두 기다릴 수있는 언급하지 않았습니다 Task.WhenAll
.
var task1 = DoWorkAsync();
var task2 = DoMoreWorkAsync();
await Task.WhenAll(task1, task2);
주요 차이점 Task.WaitAll
과 Task.WhenAll
전 의지 블록 (하여 유사한이다 Wait
후자 동안 단일 작업에서)이 모든 작업이 완료 될 때까지 호출자에게 제어를 다시 산출 기다리게 될 수 없다.
따라서 예외 처리는 다릅니다.
Task.WaitAll
:
하나 이상의 Task 인스턴스가 취소되었거나 하나 이상의 Task 인스턴스를 실행하는 동안 예외가 발생했습니다. 작업이 취소 된 경우 AggregateException에는 InnerExceptions 컬렉션에 OperationCanceledException이 포함됩니다.
Task.WhenAll
:
제공된 작업 중 하나가 오류 상태에서 완료되면 반환 된 작업도 오류 상태에서 완료됩니다. 여기에는 예외에 제공된 각 작업의 래핑되지 않은 예외 집합이 포함됩니다.
제공된 작업 중 하나라도 오류가 발생했지만 그 중 하나 이상이 취소 된 경우 반환 된 작업은 취소됨 상태로 종료됩니다.
오류가 발생한 작업이없고 취소 된 작업이 없으면 결과 작업은 RanToCompletion 상태로 종료됩니다. 제공된 배열 / 열거 가능한 작업이없는 경우 반환 된 작업은 호출자에게 반환되기 전에 즉시 RanToCompletion 상태로 전환됩니다.
답변
다음과 같은 많은 작업을 만들 수 있습니다.
List<Task> TaskList = new List<Task>();
foreach(...)
{
var LastTask = new Task(SomeFunction);
LastTask.Start();
TaskList.Add(LastTask);
}
Task.WaitAll(TaskList.ToArray());
답변
내가 본 가장 좋은 옵션은 다음 확장 방법입니다.
public static Task ForEachAsync<T>(this IEnumerable<T> sequence, Func<T, Task> action) {
return Task.WhenAll(sequence.Select(action));
}
다음과 같이 호출하십시오.
await sequence.ForEachAsync(item => item.SomethingAsync(blah));
또는 비동기 람다로 :
await sequence.ForEachAsync(async item => {
var more = await GetMoreAsync(item);
await more.FrobbleAsync();
});
답변
당신은 사용할 수 있습니다 WhenAll
awaitable 반환하는 Task
또는 WaitAll
더 리턴 유형이없는과에 더 코드 실행 시뮬을 차단합니다 Thread.Sleep
모든 작업이 완료 취소 또는 폴트 때까지.
예
var tasks = new Task[] {
TaskOperationOne(),
TaskOperationTwo()
};
Task.WaitAll(tasks);
// or
await Task.WhenAll(tasks);
당신이 praticular 순서로 작업을 실행하려는 경우 양식 영감을 얻을 수있는 이 anwser를.
답변
Task
s 를 체인으로 연결 하시겠습니까 , 아니면 병렬로 호출 할 수 있습니까?
체인의 경우
그냥 그런 짓을
Task.Run(...).ContinueWith(...).ContinueWith(...).ContinueWith(...);
Task.Factory.StartNew(...).ContinueWith(...).ContinueWith(...).ContinueWith(...);
결함이있을 수 있으므로 Task
각각 의 이전 인스턴스 를 확인하는 것을 잊지 마십시오 ContinueWith
.
병렬 방식으로
가장 간단한 방법은 다음과 같습니다. Parallel.Invoke
그렇지 않으면 s를 Task.WaitAll
사용 WaitHandle
하여 0 동작 남은 횟수에 카운트 다운을 수행 할 수도 있습니다 (대기, 새 클래스가 있습니다 CountdownEvent
) 또는 …
답변
이것이 Func <> 배열로 수행하는 방법입니다 .
var tasks = new Func<Task>[]
{
() => myAsyncWork1(),
() => myAsyncWork2(),
() => myAsyncWork3()
};
await Task.WhenAll(tasks.Select(task => task()).ToArray()); //Async
Task.WaitAll(tasks.Select(task => task()).ToArray()); //Or use WaitAll for Sync
답변
또 다른 대답 …하지만 일반적으로 데이터를 동시에로드하고 변수와 같은 변수에 넣어야하는 경우가 있습니다.
var cats = new List<Cat>();
var dog = new Dog();
var loadDataTasks = new Task[]
{
Task.Run(async () => cats = await LoadCatsAsync()),
Task.Run(async () => dog = await LoadDogAsync())
};
try
{
await Task.WhenAll(loadDataTasks);
}
catch (Exception ex)
{
// handle exception
}