Dot-Net

將 CancellationToken 作為參數傳遞給 Task.Run 有什麼好處?

  • December 19, 2019

顯然我意識到它使我能夠取消任務,但是這段程式碼無需將令牌傳遞給 Task.Run 即可達到相同的效果

有什麼實際區別?謝謝。

Dim cts As New CancellationTokenSource
Dim ct As CancellationToken = cts.Token
Task.Run(Sub()
            For i = 1 To 1000
                Debug.WriteLine(i)
                ct.ThrowIfCancellationRequested()
                Threading.Thread.Sleep(10)
            Next
        End Sub)

cts.CancelAfter(500)

VS

Dim cts As New CancellationTokenSource
Dim ct As CancellationToken = cts.Token
Task.Run(Sub()
            For i = 1 To 1000
                Debug.WriteLine(i)
                ct.ThrowIfCancellationRequested()
                Threading.Thread.Sleep(10)
            Next
        End Sub, ct)

cts.CancelAfter(500)

API docs forTask.Run(Action, CancellationToken)有這樣的評論:

如果在任務開始執行之前請求取消,則任務不會執行。相反,它被設置為 Canceled 狀態並引發 TaskCanceledException 異常。

因此,在您的場景中,沒有任何實際區別,因為您在發出取消之前等待 500 毫秒。在那段時間內,任務被安排,開始執行,並在發出取消之前多次執行循環,表現為從ct.ThrowIfCancellationRequested().

Task.Run(Action)與您的範例的此修改版本之間的區別Task.Run(Action, CancellationToken)更加明顯:

Try
   Dim cts As New CancellationTokenSource
   Dim ct As CancellationToken = cts.Token

   cts.Cancel()

   Dim task As Task = Task.Run(
       Sub()
           Console.WriteLine("Started running your code!")
           ct.ThrowIfCancellationRequested()
           Console.WriteLine("Finished running your code!")
       End Sub, ct)

   task.Wait()

Catch ex As AggregateException
   Console.Error.WriteLine("Caught exception: " & ex.InnerException.Message)
End Try

Console.WriteLine("Done, press Enter to quit.")
Console.ReadLine()

在這種情況下,Task.Run安排任務執行,但還將取消令牌與該任務相關聯。當我們呼叫task.Wait()時,線上程池執行任務之前,它會檢查取消令牌,並註意到該令牌已發出取消,因此它決定在執行任務之前取消。所以輸出是:

Caught exception: A task was canceled.
Done, press Enter to quit.

如果您改為替換: End Sub, ct)with End Sub),則執行緒池不知道取消令牌,因此即使您發出了取消,它也會繼續執行任務,然後您的任務程式碼本身會檢查取消。所以輸出是:

Started running your code!
Caught exception: The operation was canceled.
Done, press Enter to quit.

(您可以看到,這兩種情況下的異常消息也略有不同。)

總之,向Task.Run方法提供取消令牌允許執行緒池本身線上程池有機會執行任務之前知道任務是否被取消。這允許執行緒池通過甚至不費心開始執行任務來節省時間和資源。

引用自:https://stackoverflow.com/questions/48312544