使用CancellationToken-而不是Thread.Sleep

本文介绍了在服务停止和关闭操作中,使用`Thread.Sleep`可能导致的问题,即长时间阻塞可能导致服务管理器强制关闭服务。建议改用`CancellationToken`以实现可取消的任务,从而避免异常和日志填充。
摘要由CSDN通过智能技术生成

介绍 (Introduction)

Not so long ago, I was asked to take a look at a service which was intermittently generating exceptions on stop and shutdown operations.

不久前,我被要求看一下一项服务,该服务间歇性地在停止和关闭操作上生成异常。

The service itself was a simple device management component, using a task to connect to a remote device when it had booted up, doing some updates and that was sort of it. But the target device was not always ready when the connection attempt was made, so a while loop was used with a pause injected in the form of a call to Thread.Sleep(20000).

该服务本身是一个简单的设备管理组件,它使用一个任务在启动时连接到远程设备,进行一些更新,仅此而已。 但是,当尝试进行连接时,目标设备并不总是准备就绪,因此使用了while循环,并以对Thread.Sleep(20000)的调用的形式注入了暂停。

The idea of pausing a task for 20 seconds odd, before trying again makes perfect sense - but the 20 second thread block would intermittently, dependent on timing, cause the service manager to forcibly kill off the service due to shutdown or stop timeouts being triggered, and resulting exceptions would fill the logs.

在再次尝试之前将任务暂停20秒的想法非常合理-但是20秒线程块会间歇性地(取决于时间),导致服务管理器由于关机或触发触发触发而强行终止服务,并且产生的异常将填充日志。

Thread.Sleep(n) cannot be cancelled - instead, consider using the CancellationToken.WaitHandle.WaitOne(n).

不能取消Thread.Sleep(n) -相反,请考虑使用CancellationToken.WaitHandle.WaitOne(n)

使用代码 (Using the Code)

The code in this tip is a little sample of how Thread.Sleep and CancellationToken.WaitHandle.WaitOne behave in tasks, that you can experiment with.

本技巧文章中的代码是Thread.SleepCancellationToken.WaitHandle.WaitOne在任务中的行为的一些示例,您可以尝试使用它们。

The original while loop implemented in the service looked something like this:

在服务中实现的原始while循环如下所示:

while (!cancellationToken.IsCancellationRequested)
{
    // Processing
    if(connectionReady)
    {
        // Do its business
        break;
    }
    // Pause for 20 seconds before trying again
    Thread.Sleep(20000);
}

In this implementation, the thread will be blocked for 20 seconds - irrespective of any cancellation triggers. This was the underlying problem - dependent on the timing of the stop operation in relation to the Thread.Sleep call, the service manager would timeout the stop operation and forcibly kill the management service.

在此实现中,线程将被阻塞20秒-不管是否有任何取消触发器。 这是潜在的问题-根据与Thread.Sleep调用相关的停止操作的时间,服务管理器将使停止操作超时并强行终止管理服务。

Pausing code execution, but being cancellation request aware is simple enough:

暂停执行代码,但知道取消请求很简单:

while (!cancellationToken.IsCancellationRequested) 
{ 
    // Processing
    if(connectionReady)
    {
        // Do its business
        break;
    }
    // Pause for 20 seconds before trying again - now with cancellation support
    var cancellationTriggered = cancellationToken.WaitHandle.WaitOne(20000);
}

This one line change achieves the same 20 second pause that the original implementation did, and it is also task cancellation aware.

这一行更改实现了与原始实现相同的20秒暂停,并且它也知道任务取消。

兴趣点 (Points of Interest)

If you find Thread.Sleep(n) used around the place, consider switching to using the CancellationToken.WaitHandle.WaitOne(n) method instead. It will help in keeping the exceptions log down to size.

如果在该位置周围发现Thread.Sleep(n) ,请考虑改用CancellationToken.WaitHandle.WaitOne(n)方法。 这将有助于保持异常记录的大小。

翻译自: https://www.codeproject.com/Tips/5267935/Use-CancellationToken-not-Thread-Sleep

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值