【发布时间】:2015-11-30 21:07:38
【问题描述】:
我创建了一小段代码用于并行运行多个异步操作(Parallel 类本身不适用于异步操作)。
看起来像这样:
public static async Task ForEachAsync<T>(this IEnumerable<T> source, int dop, Func<T, Task> body)
{
var chunks = source.Chunk(dop);
foreach (var chunk in chunks)
await Task.WhenAll(chunk.Select(async s => await body(s).ContinueWith(t => ThrowError(t))));
}
private static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> source, int chunksize)
{
while (source.Any())
{
yield return source.Take(chunksize);
source = source.Skip(chunksize);
}
}
private static void ThrowError(Task t)
{
if (t.IsFaulted)
{
if (t.Exception.InnerExceptions != null && t.Exception.InnerExceptions.Count == 1)
throw t.Exception.InnerExceptions[0];
else
throw t.Exception;
}
}
就并行运行任务而言,上述代码运行良好。但是,当抛出异常时,我确实会遇到一些问题。
就返回异常消息而言,异常捕获代码运行良好,但堆栈跟踪还有很多不足之处 - 因为它指向 ThrowError 方法,而不是最初生成异常的方法。我可以按自己的方式工作并找出附加的调试器出了什么问题,但是如果我发布此应用程序,我将没有该选项可用 - 充其量,我会记录堆栈跟踪的异常。
那么 - 在运行异步任务时,有什么方法可以获得更有意义的堆栈跟踪?
PS。这是针对 WindowsRT 应用程序的,但我认为问题不仅限于 WindowsRT……
【问题讨论】:
-
不是问题的重点,但
Chunk具有二次时间复杂度,并且由于源的重复枚举而超慢。 -
@usr 也许是这样,但它是一个很好的干净代码,目前,应用程序没有性能问题。我会记住这一点,我可能会在某个时候更新代码。处理的元素数量可能永远不会超过几百个。
标签: c# async-await