C# 如何使用异步方法正确编写Parallel.For
如何构造下面的代码,以便调用异步方法C# 如何使用异步方法正确编写Parallel.For,c#,.net,task-parallel-library,async-await,C#,.net,Task Parallel Library,Async Await,如何构造下面的代码,以便调用异步方法 Parallel.For(0, elevations.Count(), delegate(int i) { allSheets.AddRange(await BuildSheetsAsync(userID, elevations[i], includeLabels)); }); 我建议你看看我几天前问的这个问题,最后我回答了自己,基本上我在寻找一种并行和异步的ForEach方法 该方法使用信号量lim并行处理事物,并接受异步方法作为输入操作 您可能还
Parallel.For(0, elevations.Count(), delegate(int i)
{
allSheets.AddRange(await BuildSheetsAsync(userID, elevations[i], includeLabels));
});
我建议你看看我几天前问的这个问题,最后我回答了自己,基本上我在寻找一种并行和异步的ForEach方法 该方法使用
信号量lim
并行处理事物,并接受异步方法作为输入操作
您可能还想看看我在回答末尾提供的两个链接,它们对实现这种行为非常有帮助,并且它们还包含使用分区器来实现这一点的另一种方法
就我个人而言,我不喜欢并行的;我想要所有的“异步”:)
这里是:Parallel.For()
与async
方法不兼容。如果您不需要限制并行度(即,您可以同时执行所有任务),只需启动所有任务
s,然后等待它们完成:
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();
var tasks=Enumerable.Range(0,elevations.Count())
.Select(i=>BuildSheetsAsync(userID,elevations[i],includeLabels));
列出所有工作表=(等待任务.WhenAll(任务))。选择many(x=>x).ToList();
在Parallel中调用异步方法的最简单方法。对于,下面是:
Parallel.For(0, elevations.Count(), async i =>
{
allSheets.AddRange(await BuildSheetsAsync(userID, elevations[i], includeLabels));
});
==============
评论中提到的绝对正确,在这种情况下,您可能有未观察到的例外情况。这绝对是非常重要的事情,您应该始终牢记这一点,然后处理异步委托
在这种情况下,如果您认为会出现异常,可以在委托内使用try/catch
block。或者在某些情况下,如果您的情况适合,您可以在活动上订阅。您可以尝试我正在使用的代码。它使用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();
}
}
}
任何建议请告诉我。+1,除此之外,信号量lim
显然在OP的情况下是不需要的。我还建议您在代码中使用带超时的CancellationTokenSource
而不是Timer
对象。我无法添加它要求的IEnumerable列表集合。我怎样才能让它工作?var task=Enumerable.Range(0,elevations.Length)。选择(i=>BuildSheetsAsync(userID,elevations[i],includeLabels));List allSheets=新列表();allSheets.AddRange(wait Task.WhenAll(Task));当I allSheets.AddRange(wait Task.WhenAll(Task))@啊,我没有注意到BuildSheetsAsync()
已经返回了一个集合。如果要从集合集合中生成单个集合,可以使用SelectMany()
。要从IEnumerable
集合中列出一个列表,请使用ToList()
“Parallel.For()与异步方法不兼容。”-为什么它们不能很好地协同工作?它们是帮助提高CPU效率的两个不同概念。“如果您不需要限制并行度…”-做出这种假设似乎适得其反。一个好的程序会根据其运行的服务器的功能故意限制并行度,这可能会发生变化。@Sean它们不能很好地协同工作,因为对于wait
,处理在返回的任务完成时结束,而不是在函数返回时结束。但是,Parallel.For
不理解这一点,并假设函数在返回时结束。限制并行度可能很重要,但也可能很复杂。如果我不知道复杂的方法是否有必要,我建议从简单的方法开始。你会如何设置一个最大并行度的限制,就像你对并行的限制一样。例如?这会导致错误。异步委托返回任务
,并行构造不等待该任务。这意味着异常是未被观察到的,在<代码>并行之后您不能确定。对于< /代码>,调用已经运行,所有的工作实际上已经完成(也不能很容易地验证)。可能的副本似乎不考虑当代码>动作(项)< /代码>引发异常时的情况。
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");