Uruchamianie wielu zadań asynchronicznych i oczekiwanie na ich wykonanie
Muszę uruchomić wiele zadań asynchronicznych w aplikacji konsolowej i poczekać, aż wszystkie zostaną ukończone przed dalszym przetwarzaniem.
Jest wiele artykułów, ale wydaje mi się, że im więcej czytam, tym bardziej się mylę. Przeczytałem i zrozumiałem podstawowe zasady biblioteki zadań, ale najwyraźniej gdzieś brakuje mi linku.
Rozumiem, że możliwe jest łączenie zadań tak, aby zaczynały się po kolejnych zakończeniach (co jest w zasadzie scenariuszem dla wszystkich artykułów, które mam Czytaj), ale chcę, aby wszystkie moje zadania działały w tym samym czasie i chcę wiedzieć, kiedy wszystkie zostaną ukończone.
Jaka jest najprostsza realizacja takiego scenariusza?
6 answers
Obie odpowiedzi nie wspominały o oczekiwaniu Task.WhenAll
:
var task1 = DoWorkAsync();
var task2 = DoMoreWorkAsync();
await Task.WhenAll(task1, task2);
Główna różnica między Task.WaitAll
i Task.WhenAll
jest to, że pierwszy blokuje (podobnie jak użycie Wait
na jednym zadaniu), podczas gdy drugi nie będzie i może być oczekiwany, dając kontrolę z powrotem do wywołującego, dopóki wszystkie zadania nie zakończą się.
Bardziej, obsługa wyjątków różni się:
Task.WaitAll
:
Co najmniej jedna instancja zadania została anulowana-lub-wyjątek został wyrzucony podczas wykonywania co najmniej jednego z wystąpień zadania. Jeśli zadanie zostało anulowane, obiekt AggregateException zawiera obiekt Operationcanceledexceptions w kolekcji InnerExceptions.
Task.WhenAll
:
Jeśli któreś z dostarczonych zadań zakończy się w stanie uszkodzonym, zwrócone zadanie również zakończy się w stanie uszkodzonym, gdzie jego wyjątki będą zawierały agregację zestawu rozpakowanych WYJĄTKÓW z każdego dostarczonego zadania.
Jeśli brak z dostarczonych zadań, które zostały uszkodzone, ale co najmniej jedno z nich zostało anulowane, zwrócone zadanie zakończy się w stanie anulowanym.
Jeśli żadne z zadań nie zostało popełnione i Żadne z zadań nie zostało anulowane, powstałe zadanie zakończy się w stanie RanToCompletion. Jeśli dostarczona tablica / enumerable nie zawiera żadnych zadań, zwrócone zadanie natychmiast przejdzie do stanu RanToCompletion, zanim zostanie zwrócone do wywołującego.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-28 11:52:55
Możesz utworzyć wiele zadań takich jak:
List<Task> TaskList = new List<Task>();
foreach(...)
{
var LastTask = new Task(SomeFunction);
LastTask.Start();
TaskList.Add(LastTask);
}
Task.WaitAll(TaskList.ToArray());
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-19 07:34:44
Najlepszą opcją jaką widziałem jest następująca metoda rozszerzenia:
public static Task ForEachAsync<T>(this IEnumerable<T> sequence, Func<T, Task> action) {
return Task.WhenAll(sequence.Select(action));
}
Nazwij to tak:
await sequence.ForEachAsync(item => item.SomethingAsync(blah));
Lub z asynchronicznym lambda:
await sequence.ForEachAsync(async item => {
var more = await GetMoreAsync(item);
await more.FrobbleAsync();
});
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-13 20:52:41
Czy chcesz połączyć Task
s, czy można je wywoływać równolegle?
Do łączenia
Po prostu zrób coś takiego
Task.Run(...).ContinueWith(...).ContinueWith(...).ContinueWith(...);
Task.Factory.StartNew(...).ContinueWith(...).ContinueWith(...).ContinueWith(...);
I nie zapomnij sprawdzić poprzedniej instancji Task
w każdej ContinueWith
, ponieważ może ona zostać uszkodzona.
Dla sposobu równoległego
Najprostsza metoda, na jaką natknąłem się: Parallel.Invoke
W przeciwnym razie jest Task.WaitAll
możesz też użyć WaitHandle
s do wykonania odliczania do zera (poczekaj, jest nowy Klasa: CountdownEvent
), albo ...
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-29 07:09:16
Możesz użyć WhenAll
który zwróci oczekiwany Task
lub WaitAll
który nie ma typu return i zablokuje dalsze wykonywanie koduThread.Sleep
dopóki wszystkie zadania nie zostaną ukończone, anulowane lub usunięte.
Przykład
var tasks = new Task[] {
await TaskOperationOne(),
await TaskOperationTwo()
};
Task.WaitAll(tasks);
// or
await Task.WhenAll(tasks);
Jeśli chcesz uruchomić zadania w praktycznej kolejności, możesz uzyskać inspirację w formularzu Ten anwser.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-23 22:28:02
Tak to robię z tablicą 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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:46:20