【问题标题】:Running tasks sequentially: how to deal with exceptions?顺序运行任务:如何处理异常?
【发布时间】:2014-03-09 05:01:58
【问题描述】:

根据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 btw。

【问题讨论】:

  • 您可能有兴趣查看thisthis

标签: c# async-await


【解决方案1】:

您的代码不起作用的原因是因为您几乎要求它预测未来。

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);
}

【讨论】:

    【解决方案2】:

    也许你可以实现某种队列。

    这样,如果一个任务失败,只有那个任务会返回异常,队列中的下一个任务将被执行。你将能够处理异常,我不知道,也许再次入队任务;)

    但这只是一个想法!我希望这会有所帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多