在Service中RunAsync方法的while循环中首选的是:使用IsCancellationRequested或抛出异常

时间:2016-05-30 11:57:12

标签: azure-service-fabric

为什么新的Service Fabric代码的示例RunAsync构造如下

protected override async Task RunAsync(CancellationToken cancellationToken)
{
  while(true)
  {
    cancellationToken.ThrowIfCancellationRequested();

    await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
  }
} 

而不是

protected override async Task RunAsync(CancellationToken cancellationToken)
{
  while(cancellationToken.IsCancellationRequested)
  {
    await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
  }
} 

没有抛出的版本不是首选吗? The docs声明两种实现都是正确的:“系统将等待您的任务结束(通过成功完成,取消或故障)”。

3 个答案:

答案 0 :(得分:4)

简短回答 - 两者都很好。我使用ThrowIfCancellationRequested,因为IMO是更安全的选择。它也更加一致 - 调用链中较低的方法可以通过异常传播取消。

每当RunAsync中发生异常时,Service Fabric reports发生一个瞬态错误(这意味着重新启动服务而不重新创建实例/副本)。

它为OperationCanceledException提供了特殊处理 - 如果它被传递给方法的取消令牌抛出,则认为该方法已被成功取消,并且不会报告任何错误。

您可以通过监控Microsoft-ServiceFabric-Services ETW事件来自行尝试。

答案 1 :(得分:0)

cancelToken.ThrowIfCancellationRequested();

等于

if(令牌。IsCancellationRequested)     抛出新的OperationCanceledException(token);

通常,人们将其用作一种控制机制,以确保当前处理被中止而不会潜在地运行任何额外的代码。另外,调用ThrowIfCancellationRequested()时无需检查取消情况

答案 2 :(得分:0)

这甚至更简单,也可以工作:

protected override async Task RunAsync(CancellationToken cancellationToken)
{
    while(true)
    {
        await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
    }
}

protected override async Task RunAsync(CancellationToken cancellationToken)
{
    while(cancellationToken.IsCancellationRequested)
    {
        await Task.Delay(TimeSpan.FromSeconds(1));
    }
}

我发现了这一点,因为我的代码是按照如下示例代码建模的:

protected override async Task RunAsync(CancellationToken cancellationToken)     
{
    var pipeline = ...
    pipeline.Start();

    while (true) {
        if (cancellationToken.IsCancellationRequested) {
            ServiceEventSource.Current.ServiceMessage(Context, "Stopping pipeline");
            await pipeline.ShutdownAsync();
        }

        cancellationToken.ThrowIfCancellationRequested();

        await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
    }
}

并且管道从未停止过。解决方案是不使用cancellationToken调用中的Task.Delay