Как бы я структурировал код ниже, чтобы вызвать метод async?
Parallel.For(0, elevations.Count(), delegate(int i)
{
allSheets.AddRange(await BuildSheetsAsync(userID, elevations[i], includeLabels));
});
Как бы я структурировал код ниже, чтобы вызвать метод async?
Parallel.For(0, elevations.Count(), delegate(int i)
{
allSheets.AddRange(await BuildSheetsAsync(userID, elevations[i], includeLabels));
});
Parallel.For()
не работает с методами async
. Если вам не нужно ограничивать степень parallelism (т.е. вы все в порядке со всеми выполняемыми задачами одновременно), вы можете просто запустить все Task
, а затем дождаться их завершения:
var tasks = Enumerable.Range(0, elevations.Count())
.Select(i => BuildSheetsAsync(userID, elevations[i], includeLabels));
List<Bitmap> allSheets = (await Task.WhenAll(tasks)).SelectMany(x => x).ToList();
Я бы порекомендовал вам взглянуть на этот вопрос, который я задал несколько дней назад, и в конечном итоге ответил сам, в основном я искал параллельный и асинхронный метод ForEach.
Метод использует SemaphoreSlim
для обработки вещей параллельно и принимает асинхронные методы как действие ввода.
Вы также можете взглянуть на две ссылки, которые я предоставил в конце моего ответа, они действительно были полезны для реализации такого поведения, и они также содержат другой способ сделать это, используя Partitioner
.
Лично мне не понравился Parallel.For
, потому что это синхронный вызов, как описано в ссылках, которые я дал; Я хотел все "асинхронно": -)
Вы можете попробовать этот код, который я использую. он использует foreach и SemaphoreSlim для достижения параллельной асинхронности.
public static class ParallelAsync
{
public static async Task ForeachAsync<T>(IEnumerable<T> source, int maxParallelCount, Func<T, Task> action)
{
using (SemaphoreSlim completeSemphoreSlim = new SemaphoreSlim(1))
using (SemaphoreSlim taskCountLimitsemaphoreSlim = new SemaphoreSlim(maxParallelCount))
{
await completeSemphoreSlim.WaitAsync();
int runningtaskCount = source.Count();
foreach (var item in source)
{
await taskCountLimitsemaphoreSlim.WaitAsync();
Task.Run(async () =>
{
try
{
await action(item).ContinueWith(task =>
{
Interlocked.Decrement(ref runningtaskCount);
if (runningtaskCount == 0)
{
completeSemphoreSlim.Release();
}
});
}
finally
{
taskCountLimitsemaphoreSlim.Release();
}
}).GetHashCode();
}
await completeSemphoreSlim.WaitAsync();
}
}
}
использование:
string[] a = new string[] {
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"10",
"11",
"12",
"13",
"14",
"15",
"16",
"17",
"18",
"19",
"20"
};
Random random = new Random();
await ParallelAsync.ForeachAsync(a, 2, async item =>
{
Console.WriteLine(item + " start");
await Task.Delay(random.Next(1500, 3000));
Console.WriteLine(item + " end");
});
Console.WriteLine("All finished");
любое предложение, пожалуйста, дайте мне знать.
Самый простой способ вызвать ваш асинхронный метод внутри Parallel.For
следующий:
Parallel.For(0, elevations.Count(), async i =>
{
allSheets.AddRange(await BuildSheetsAsync(userID, elevations[i], includeLabels));
});
==============
MarioDS в комментарии полностью упоминается, что в этом случае у вас могут быть незаметные исключения. И это определенно очень важная вещь, которую вы всегда должны учитывать, а затем иметь дело с асинхронными делегатами.
В этом случае, если вы считаете, что у вас есть исключения, вы можете использовать блок try/catch
внутри делегата. Или в некоторых случаях, если ваша ситуация подходит для вас, вы можете подписаться на TaskScheduler.UnobservedTaskException событие.