【问题标题】:Task WhenAll exception任务WhenAll异常
【发布时间】:2021-05-01 06:46:30
【问题描述】:

我必须执行大约 10 个任务,然后获得它们的结果(都不同)。我创建了一个包装器来捕获异常,我不想知道哪个失败了,但如果失败了,它不应该继续。我也为此使用了WhenAll,但问题是我得到了每个结果的结果并且我得到了一个未处理的异常,如果我的包装器有任何异常,有没有办法不继续?

 var 1Task = api.1TaskAsync();
 var 2Task = api.2TaskAsync();
 var 3Task = api.3TaskAsync();

await taskService.RunSafeAsync(() => Task.WhenAll(1Task, 2Task, 3Task));

var result = await 1Task;  <-------------exception

任务服务:

public async Task RunSafeAsync(Func<Task> task) 
{ 
    try 
    {           
        await task();
    }
    catch (Exception ex)
    {

    }
}

【问题讨论】:

  • 您是否试图在这些任务中的第一个异常之后中断/取消所有任务?
  • 等待 taskService.RunSafeAsync (() => Task.WhenAll (1Task, 2Task, 3Task));如果上面出现任何异常,我不希望它继续 var result = await 1Task 我必须在 RunSafeTask 中返回任何 true 或 false 吗?
  • RunSafeAsync 方法对我来说看起来不太安全,因为它会吞下异常!如果这是故意的,那么该方法的更好名称可能是WhenAllNoThrow。在这种情况下,我会质疑这种方法的有用性。您可以直接在调用站点上使用try/catchtry { await Task.WhenAll(Task1, Task2, Task3); } catch { return; }。作为旁注,在 C# 中变量名称以数字开头是非法的。
  • RunSafeAsync sn-p 只是我代码的一部分,它不完整,变量名只是一个例子,以使其更快,我知道它们违反了规则。

标签: c# .net async-await


【解决方案1】:

您无法从发生故障的函数中检索结果。它没有结果——因为它从未完成。尝试检索其结果(如您所愿)将引发异常,因为没有任何内容可以分配给应该接受返回值的变量。

为避免这种情况,请在尝试检索结果之前检查任务是否出错。

var 1Task = api.1TaskAsync();
var 2Task = api.2TaskAsync();
var 3Task = api.3TaskAsync();

await taskService.RunSafeAsync(() => Task.WhenAll(1Task, 2Task, 3Task));

if (!1Task.IsFaulted)
{
    var result = await 1Task;  

【讨论】:

  • 很好的答案!我只是将await 1Task 替换为1Task.Result,因为它已经在等待并且结果已经准备好了。
  • Task.Result,能不能带来麻烦?
  • @angelru 在这种情况下不是。如果没有等待任务并且 Result 属性还没有价值,那是个坏主意。但是在等待之后,Result 属性将返回而不会阻塞
【解决方案2】:

如果您只想在任何方法中出现异常时继续,则不要包装 WhenAll 并在抛出时做出反应。

try 
{
   await Task.WhenAll(...);
   // None of the tasks threw an exception;
} 
catch (Exception ex)
{
  // One or more tasks threw an exception 
  return / throw / etc. 
}

//Continue the happy path

取消令牌

如果您需要同时尝试任务并在其中一项失败时中止所有任务,那么您需要查看取消令牌并在发生任何异常时激活令牌(不是在整个 WhenAll 中的 catch,而是每个任务都必须在try..catch 中执行。

也许顺序?

顺便说一句。使用.WhenAll 将尝试所有任务。也许你真的想按顺序执行任务,只有在没有异常的情况下才继续:

try 
{
    await F1();
    await F2();
}
catch(Exception ex)
{
}

这看起来并不圆滑,但它清楚地表明除非任务 1 成功,否则任务 2 将不会运行。

【讨论】:

  • 这个想法是尝试并捕获包装器以传递给我的所有任务,而无需将其放入应用程序的各个部分
  • 我会赞成这个答案,如果不是“也许 foreach?”部分。启动多个任务并一个一个地等待它们注定会导致即发即弃的任务。这很少是一个好主意。
  • @TheodorZoulias 公平点。我为未开始的任务编写了片段,但这并不常见。我重写了该部分并澄清了我的意思。
猜你喜欢
  • 1970-01-01
  • 2020-11-05
  • 2014-09-27
  • 2023-01-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-27
相关资源
最近更新 更多