【问题标题】:Cannot await async task无法等待异步任务
【发布时间】:2018-10-29 14:38:20
【问题描述】:

我有一个名为StartAsync 的方法等待不同的任务,这是设计:

public async Task StartAsync(int instance)
{
    await SomeController.Foo();
    await AnotherController.Foo2();
}

现在我需要多次运行StartAsync方法,所以我创建了不同的Task,这样我可以管理Task的单次执行StartAsync

Task bot1 = new Task(async () => { await new Bot().StartAsync(1); });

Task bot2 = new Task(async () => { await new Bot().StartAsync(2); });

这些Tasks可以通过输入启动,本质上,如果用户按下1,那么bot1任务就会启动:

public async Task<bool> StartBotInstanceAsync(int instance)
{
     try  
     {
          switch(instance)
          {
              case 1:
                  await bot1.Start(); //<- Problem here
                  break;

              case 2:
                  bot2.Start(); 
                  break;
          }

          return true;
     }
     catch(Exception ex)
     {
         Logger.Info(ex.ToString());
         return false;
     }
}

基本上,当 try catch 块中发生异常时,我需要写一个日志,但为此我需要等待Task 结果,不幸的是我收到了这个错误:

不能等待 void

await bot1.Start();

在这种情况下如何管理异常?

【问题讨论】:

  • Start != StartAsync - 你的意思是写await bot1.StartAsync();
  • @Default bot1.Start() 是一个包含Taskawait new Bot().StartAsync(1);
  • 不需要需要冷任务来拨打多个电话。 await 不启动任务,它等待一个已经在运行的任务。这意味着您可以将多次调用返回的任务存储到Bot.StartAsync 并单独或一次等待它们,例如await Task.WhenAll(task1,task2);
  • 如果您能清楚地描述您要解决的问题,那将是一个开始。目前,您似乎只是在这个问题上抛出 awaitTask 并试图让它编译而没有明确的 spec 来实现您想要实现的目标(或者如果你有这样的规范,你还没有与我们分享)
  • @JuveMerda 您不需要任何代码来捕获异常。你需要解释你实际上想要做什么。为什么不创建一个 simple 方法来创建一个新机器人并在 try/catch 中等待任务?您是否要创建多个机器人实例,在这种情况下您需要一个 Bot[] 数组?

标签: c# exception task


【解决方案1】:

如果您希望使用当前的结构,那么您将需要 2 个单独的语句。

case 1:
    bot1.Start();
    await bot1;
    break;

【讨论】:

  • 使用冷任务是根本问题。这只是掩盖它
【解决方案2】:

如果要使用多个bot实例,请将它们存储在一个数组中,并使用instance参数作为索引,例如:

_bots=new[]{ new Bot(),new Bot()};

public async Task<bool> StartBotInstanceAsync(int instance)
{
     try  
     {
          await _bots[instance-1].StartAsync();
          return true;
     }
     catch(Exception ex)
     {
         Logger.Info(ex.ToString());
         return false;
     }
}

甚至更好:

public async Task<bool> StartBotInstanceAsync(Bot bot)
{
     try  
     {
          await bot.StartAsync();
          return true;
     }
     catch(Exception ex)
     {
         Logger.Info(ex.ToString());
         return false;
     }
}

var myBot=_bots[instance-1];
var started=await StartBotInstanceAsync(myBot);

使用将机器人作为参数的async 函数可以轻松创建更复杂的流程,例如:

public async Task SomeComplexFlow(Bot bot)
{
    try
    {
        await bot.StartAsync();
        await bot.DoSomething();
        ...
    }
    catch(Exception exc)
    {
        ...
    }
}


var myBot=_bots[instance-1];
await SomeComplexFlow(myBot);

也可以等待多个任务完成。可以使用Task.WhenAll 等待所有机器人终止,例如:

await Task.WhenAll(_bots[0].StopAsync()...);

或者,更好:

var tasks=_bots.Select(bot=>bot.StopAsync());
await Tasks.WhenAll(tasks);

【讨论】:

  • 感谢您的数组建议,我已经根据您的评论实施了您的解决方案,唯一的问题是,如果我在 SomeComplexFlow => throw new Exception("An error happened!"); 中添加它,我没有得到断点在catch 块中开火,为什么?
猜你喜欢
  • 1970-01-01
  • 2014-03-18
  • 2014-09-06
  • 2013-02-10
  • 2017-07-22
  • 1970-01-01
  • 1970-01-01
  • 2012-12-18
  • 2017-09-24
相关资源
最近更新 更多