如何避免“未观察到的任务”例外?

时间:2017-03-06 22:41:41

标签: c# .net task

我已经陷入了混乱的任务,而且我不确定一个好方法可以摆脱它。

我有数据我将从两个不同的API异步获取。这种联系是可疑的,我对我可以等待的时间有着严格的时间限制。期望的行为是“我想等待最多2秒才能获得两组数据,如果2秒过期,我将接受任何已完成的数据,即使这些都没有。”

我用这样一种笨拙的设置来解决这个问题:(它已经在工作线程上运行,因此同步等待不是问题。)

Task<IData> firstTask = _firstDataSource.GetDataAsync()
Task<IData> secondTask = _secondDataSource.GetDataAsync()

var whenBothTasksFinish = Task.WhenAll(firstTask, secondTask);

var timeoutTask = Task.Delay(TimeSpan.FromSeconds(2));

Task.WhenAny(whenBothTasksFinish, timeoutTask).Wait()

bool timedOut = timeoutTask.IsCompleted

if (timedOut) {
    return newIData[0];
}

var sources = new List<IData>();
if (firstTask.IsCompleted && !firstTask.IsFaulted) {
    sources.Add(firstTask.Result);
} else if (firstTask.IsFaulted) {
    LogException(firstTask.Exception);
}

// Same block as above for secondTask

它很乱,但是当我写这篇文章的时候,我的时间很狭窄。也许还有更好的方法,今晚我会想到这一点。现在我很困惑如何解决这个问题。

问题在关闭网络连接时发生,我的两个IData任务都失败了。由于我记录了它们的异常,因此我满足了导致UnobservedTaskException的条件。但是他们的异常也会冒泡进入Task.WhenAll(),并且可能是Task.WhenAny()。最终完成,我的应用程序抛出UnobservedTaskException。奇怪的是,这似乎不会一直使应用程序崩溃,但它确实有时这就是我担心的原因。

我环顾四周,这似乎是一种我可以处理的方式,这是一个相当简单的延续:

whenBothTasksFinish.ContinueWith(t => LogException(t.Exception), TaskContinuationOptions.OnlyOnFaulted);

我不仅仅是这样做的唯一原因是我喜欢当前结构如何让我提供更个性化的日志消息:我关心哪个任务引发了异常。我不想记录我得到的凌乱的AggregateException,但是没有太多考虑解开它。

现在已经很晚了,我没有花很多时间重新思考这个算法。有没有办法确保我承认任务异常或重组这个以获得我想要的结果而不涉及如此多的移动部件?

1 个答案:

答案 0 :(得分:1)

我尝试了很多不同的东西,并得出了这个解决方案:

  whenBothTasksFinish.ContinueWith((parent) => {
    var flattened = parent.Exception.Flatten();
    flattened.Handle((ex) => true);
  }, TaskContinuationOptions.OnlyOnFaulted);

在正常情况下,这是一个坏主意。它相当于空try/catch。但在我的场景中,我将在稍后单独处理每个异常。这使得框架退出抱怨我没有处理WhenAll(的异常。

奇怪:当我在Xamarin Studio中调试时,持续断点太久有时会导致WhenAll()任务在继续运行之前被收集。我可以通过GC.KeepAlive()来解决这个问题,但是对不起。