c# - 任务内 Parallel.Invoke 中的异常处理

标签 c# task-parallel-library

我有以下代码

var exceptions = new ConcurrentQueue<Exception>();
Task task = Task.Factory.StartNew(() =>
{
    try
    {
        Parallel.Invoke(
            async () => await _aViewModel.LoadData(_someId),
            async () => await _bViewModel.LoadData(_someId)
        );
    }
    catch (Exception ex)
    {
        exceptions.Enqueue(ex);
    }
}).ContinueWith((continuation) =>
    {
        if (exceptions.Count > 0) throw new AggregateException(exceptions);
    });

我在这里使用 Task.StartNew,因为 LoadData 方法使用 Dispatcher.StartAsync 方法在内部调用主 UI 线程。

我遇到的问题是,如果我强制 _aViewModel.LoadData 抛出异常,它不会在 Catch(Exception) 子句中捕获(如果我捕获 AggregateException 也不会)。我不明白为什么!?

最佳答案

Parallel.Invoke 不是async 感知的。所以你的 async lambdas 被转换为 async void 方法,这些方法具有非常尴尬的错误语义(它们不允许离开 async void 方法; 相反,它们被捕获并直接在 SynchronizationContext 上重新引发,该 SynchronizationContextasync void 方法启动时处于事件状态 - 在本例中为线程池)。/p>

我不确定您为什么首先使用 Parallel.Invoke。由于您的方法已经是 async,您可以这样做:

Task task = Task.Factory.StartNew(async () =>
{
    try
    {
        Task.WaitAll(
            _aViewModel.LoadData(_someId),
            _bViewModel.LoadData(_someId)
        );
    }
    catch (Exception ex)
    {
        exceptions.Enqueue(ex);
    }
})...

附言如果您有时间,请重新考虑整个代码部分的结构。 Dispatcher.StartAsync 是一种代码味道。 UI 应该(异步地)请求数据;数据检索对象不必知道 UI。

关于c# - 任务内 Parallel.Invoke 中的异常处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19793771/

相关文章:

c# - 缩进 lambda 和嵌套操作

c# - 异步任务取消最佳实践 : user versus program

c# - 如何在现有业务数据之上创建 odbc 层?

c# - 如何在 NumericUpDown 中保留有效值而不是分配最大值?

c# - 开发 WPF 应用程序 - 有什么方法可以优化 .NET 安装?

c# - 如何以编程方式更改 LINQ C# Winforms 中的连接字符串

c# - 在后台运行任务 (PCL)

c# - 使用嵌套的 Parallel.For

c# - C# 中 oracle 连接的最佳实践

c# - 什么时候应该将任务视为 "long running"?