使用CancellationToken——而不是Thread.Sleep

目錄

介紹

使用代碼

興趣點


經常發現需要在代碼執行中添加暫停,乍一看遠程目標或文件可能尚未準備好,所以您退後一段時間再試一次,重複執行直到目標準備好或過程被取消。在這種情況下,很容易放入Thread.Sleepn)——但這不會響應取消觸發器,所以爲什麼不使用CancellationToken呢?

介紹

不久前,我被要求查看一項服務,該服務間歇性地在停止和關閉操作上生成異常。

該服務本身是一個簡單的設備管理組件,它使用一個任務在啓動時連接到遠程設備,進行一些更新,僅此而已。但是,當嘗試進行連接時,目標設備並不總是準備就緒,因此使用了while循環,並以調用Thread.Sleep(20000)的形式插入了暫停。

在再次嘗試之前將任務暫停20秒的想法很合理——但是20秒線程塊會間歇性地(取決於時間)導致服務管理器由於觸發關閉或停止超時而強制關閉服務,由此產生的異常將填滿日誌。

Thread.Sleep(n)無法取消——請考慮使用CancellationToken.WaitHandle.WaitOne(n)

使用代碼

本技巧中的代碼是Thread.SleepCancellationToken.WaitHandle.WaitOne在任務中的行爲的一個小示例,您可以對其進行試驗

服務中實現的原始while循環如下所示:

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

在此實現中,線程將被阻塞20秒——不管是否有任何取消觸發器。這是潛在的問題——根據與Thread.Sleep調用有關的停止操作的時間,服務管理器將使停止操作超時並強行終止管理服務。

暫停執行代碼,但知道取消請求很簡單:

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);
}

這一行更改實現了與原始實現相同的20秒暫停,並且它也知道任務取消。

興趣點

如果您發現到處都在使用Thread.Sleep(n),請考慮改爲使用CancellationToken.WaitHandle.WaitOne(n)方法。這將有助於保持異常記錄的大小。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章