根据 svick 的建议我创建了一个小类,其目的是按顺序运行任务,也就是说,它在 ThreadPool 上安排它们,但它确保它们按照提交的顺序一个接一个地执行。它看起来像这样:
class SequentialTaskRunner<TResult> where TResult : new() {
public Task<TResult> Run(Func<TResult> func) {
var result = RunInternal(func, m_previous);
m_previous = result;
return result;
}
async Task<TResult> RunInternal(Func<TResult> func, Task<TResult> previous) {
await previous;
return await Task.Run(func);
}
Task<TResult> m_previous = Task.FromResult(new TResult());
}
现在,我遇到的问题是,如果 func() 抛出异常,那么 Run() 的每次后续调用也将返回该异常,并且无法运行新任务。我试过像这样更改 RunInternal:
async Task<TResult> RunInternal(Func<TResult> func, Task<TResult> previous) {
if (previous.Exception == null) {
await previous;
}
return await Task.Run(func);
}
但这并不可靠;如果快速提交任务,一个任务的失败仍然会导致多个任务返回相同的异常。我对为什么感到困惑,并希望得到解释。我刚刚开始使用 async/await 顺便说一句。
最佳答案
您的代码之所以不起作用,是因为您几乎是在要求它预测 future 。
当 Task
尚未完成时,其 Exception
将始终为 null
。这意味着您的 await previous
很可能会抛出异常。
这里最简单的解决方案是使用通用的catch
:
async Task<TResult> RunInternal(Func<TResult> func, Task<TResult> previous)
{
try
{
await previous;
}
catch {}
return await Task.Run(func);
}
如果您想隐藏那个空的 catch
(因为这通常是一种不好的做法),或者如果您经常这样做并希望避免重复,您可以为此编写一个辅助方法:
public static async Task IgnoreException(this Task task)
{
try
{
await task;
}
catch {}
}
用法:
async Task<TResult> RunInternal(Func<TResult> func, Task<TResult> previous)
{
await previous.IgnoreException();
return await Task.Run(func);
}
关于c# - 按顺序运行任务 : how to deal with exceptions?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22273055/