Wiem, że używanie await w foreach nie jest dobrą praktyką ze względu na wydajność, ponieważ czekałoby sekwencyjnie na każde zadanie. foreach (var task w wyniku) { task.Stages = await GetStagesForTask(...

0
DiPix 28 czerwiec 2021, 16:59

3 odpowiedzi

Najlepsza odpowiedź

Możesz użyć LINQ z delegatem asynchronicznym:

var tasks = result.Select(async task =>
{
    var stage = await GetStagesForTask(task.Id);
    task.Stages = stage;
});

await Task.WhenAll(tasks);

Lub wprowadź funkcję lokalną:

List<Task> listOfTasks = new List<Task>();

async Task SetStagesAsync(YourTask task)
{
    task.Stages = await GetStagesForTask(task.Id);
}

foreach (var task in result)
{
    listOfTasks.Add(SetStagesAsync(task));
}

await Task.WhenAll(listOfTasks);
3
Johnathan Barclay 28 czerwiec 2021, 18:40

Tak jest w przypadku równoległego dla: https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.parallel.for?view=net-5.0

Zakładając, że możesz przekonwertować wynik na listę, aby uzyskać dostęp do jej pozycji według indeksu.

W pewnym sensie jest to podobne do tego, co zaproponował @LajosArpad, ale jest to znacznie prostszy sposób, ponieważ możliwe problemy, o których wspomniał, są obsługiwane automatycznie przez środowisko wykonawcze.

-1
Ivan Ičin 28 czerwiec 2021, 14:48

Zgrabnym sposobem rozwiązania tego problemu jest utworzenie wątku dla każdego zadania, await wydarzyłoby się wewnątrz oddzielnych wątków. Więc utworzyłbyś wątki w foreach, czekałyby w osobnych wątkach, a następnie inny foreach wywołałby .Join() dla każdego wątku. W ten sposób nie będziesz mieć sekwencyjnego oczekiwania, ale utworzysz wątki, które będą działały równolegle i będziesz czekać tak długo, jak twoje najdłuższe zadanie, a nie tak długo, jak suma czasu potrzebnego na wszystkie zadania.

Jeśli jednak masz wiele zadań, uważaj na zjadanie wszystkich zasobów. Jeśli masz wiele zadań, podziel je na kawałki po około 10 wątków i zastosuj podejście, które opisałem powyżej.

-1
Lajos Arpad 28 czerwiec 2021, 14:42