【问题标题】:Schedule task and continue, in C#在 C# 中安排任务并继续
【发布时间】:2017-01-13 17:59:51
【问题描述】:

我希望我的代码安排任务并立即进行 ForeverRunningTaskAsync。这样,StopForeverRunningTask 在 ForeverRunningTaskAsync 已经进行了 5 秒时执行:

private async void button_Click(object sender, RoutedEventArgs e)
{
  Task.Delay(5000).ContinueWith((t) => { StopForeverRunningTask(); }, CancellationToken.None);
  await ForeverRunningTaskAsync();
}

运行时一切正常。但是,编译器警告我我错过了 Task.Delay 调用中的“等待”。我不想等待,因为 ForeverRunningTaskAsync 必须立即启动,而不是延迟之后。也许,有一种更优雅的方法来安排任务并立即执行后续代码?或者,我应该忽略警告吗?

编辑: StopForeverRunningTask 实际上可以做任何事情。从答案中,我看到我应该为它提供更抽象的名称。它不一定会停止 ForeverRunningTask 的执行。它可以设置一些标志、获取当前状态等(甚至在 ForeverRunningTask 运行时被多次调用),因此不能使用 CancellationToken。下面建议的 WaitAll 方法回答了我的问题。

【问题讨论】:

  • 我不确定我是否理解这个问题,你为什么要使用await?你没有使用ForeverRunningTaskAsync 的结果,也没有在它完成后做任何事情,这不是简单地启动两个不同的任务,一个等待5 秒后再执行,另一个立即启动?跨度>
  • 我只关注这两个(长期运行的任务和以某种方式控制或检查长期运行的任务流程的任务)。长时间运行的任务之前和之后都有其他任务,长时间运行的任务实际上有结果等等。我只是想做一个尽可能简单的例子,把不那么重要的细节放在一边。
  • @Alex:你不应该使用ContinueWith。创建一个单独的async 方法并改用await
  • @StephenCleary 恐怕我无法理解这一点。你能扩展一下吗?
  • @Alex:我在我的博客上解释了为什么ContinueWith is dangerous。而不是使用ContinueWith,您应该有一个单独的async 方法:private async Task StopAfterDelayAsync() { await Task.Delay(5000); StopForeverRunningTask(); },称为:var stopper = StopAfterDelayAsync();

标签: c# async-await


【解决方案1】:

您的代码中已经暗示了一种方法可以改为:CancellationToken

创建一个CancellationToken,它将在 5 秒内自动取消:

using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)))
{
    await ForeverRunningTaskAsync(cts.Token);
}

然后在您的 ForeverRunningTaskAsync() 方法中执行以下操作:

async Task ForeverRunningTaskAsync(CancellationToken cancellationToken)
{
    while (!cancellationToken.IsCancellationRequested)
    {
        // Do stuff, including passing cancellationToken on to anything
        // else that supports it
    }
}

如果这不太适合您的代码或模型,还有其他类似的方法可以使用取消令牌,但我建议以上是规范。

【讨论】:

  • 也许,我应该为方法提供更好的名称。在实际代码中,我实际上并不需要取消长时间运行的方法,而是更愿意为其提供更多数据(或获取其执行的中间结果)。 IE。 StopForeverRunningTask 实际上是SomethingWhichDealWithsPropsOfForeverRunningTask。尽管如此,从这个问题的外观来看,你的答案是绝对正确的,所以我赞成它。谢谢!
  • 请注意,这里的人只能回答您提出的问题,而不是您应该提出的问题。如果您实际上不需要取消其他任务,您可能应该写一个更符合您实际需求的问题。
  • 是的,我现在做了必要的编辑。我只是试图避免相反的问题,太多的细节掩盖了真正的问题。在简洁和复杂之间找到适当的平衡是一门真正的手艺。
【解决方案2】:

忽略这种警告通常不是一个好主意。在某些情况下,它可能不会产生任何明显的直接影响(例如在您的情况下),但它会使代码容易受到周围任何更改的影响。

你有一个选择是等到两个任务都完成

private async void button_Click(object sender, RoutedEventArgs e)
{
  var stopper = Task.Delay(5000).ContinueWith((t) => { StopForeverRunningTask(); }, CancellationToken.None);
  var runner = ForeverRunningTaskAsync();
  await Task.WhenAll(stopper, runner);
}

【讨论】:

    【解决方案3】:

    使用 CancelationTokenSource。 5 秒后您的任务会自动取消。

    var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(5000));
    
    await ForeverRunningTaskAsync(cts.Token).ConfigureAwait(false);
    

    【讨论】:

      猜你喜欢
      • 2015-01-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-14
      • 1970-01-01
      • 2012-02-22
      • 2011-05-15
      • 2015-04-10
      相关资源
      最近更新 更多