成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Dotnet線程取消的深度進階

開發 架構
在 Dotnet 里,給出了一個東西,叫取消令牌 ( Cancellation Tokens )。這個令牌,就是請求取消的載體。

取消的概念

通常我們最熟悉的,是一個方法的中止。中止是完全的。一個方法中止了,則這個方法不再往下執行,方法中前面已經完成的部分會被拋棄,并返回一個設定的結果。

取消則不同。

通常,取消是由其它代碼發出的命令,也就是說,是由一些代碼去請求取消,另一部分代碼的響應取消。而且,實際發生的情況,是請求代碼只是通知響應代碼,希望它能停止執行;響應代碼會按照自己設定的方式對取消請求做出響應,有可能立即停止任務,也有可能繼續運行下去,直到一個可以停止的點,甚至可能完全忽略這個取消請求。

概念清楚了,怎么做?

取消令牌

既然是一方請求,另一方響應,那對于響應代碼來說,重要的是能夠知道并響應取消請求。

在 Dotnet 里,給出了一個東西,叫取消令牌 ( Cancellation Tokens )。這個令牌,就是請求取消的載體。

請求代碼發起取消時,實際是發起了一個對「取消令牌」的取消操作,然后,響應代碼將對這個被取消的令牌做出正確反應。

如果看到這兒有點混亂的話,看一下示例代碼:

async Task SomethingAsync(int data, CancellationToken cancellationToken)
{
var result = await FirstStepAsync(data, cancellationToken);
await SecondStepAsync(intermediateValue, cancellationToken);
}

響應代碼基本都是這個樣子。這里面,CancellationToken 就是上面說的取消令牌。

CancellationToken 可以在任何地方被設置為取消:用戶按下取消按鈕,或客戶端斷開連接,超時,等等。重要的是,當它被設置為取消時,就表示響應代碼需要處理取消了。

注意:一個 CancellationToken 只能被取消一次。一旦它被取消,就會永遠保持取消狀態。

帶有取消令牌的方法定義

上面的示例,就是一個典型的帶有取消令牌的方法定義。

按照微軟的習慣,帶有 CancellationToken 的方法有以下約定:

  • CancellationToken 通常是最后一個參數
  • 方法通常會提供一個重載,或默認參數值,以便調用者可以不提供取消令牌而直接調用

當然,這是一個非強制的約定。如果你不介意別人看著別扭,可以不管這個約定。

看幾個例子:

Task SomethingAsync(int data) => SomethingAsync(data, CancellationToken.None);

async Task SomethingAsync(int data, CancellationToken cancellationToken)
{
...
}

async Task SomethingAsync(int data, CancellationToken cancellationToken = default)
{
...
}

在這里,CancellationToken 代表任何類型或任何原因的取消。

通過 CancellationToken 參數,方法聲明了自己可以響應取消。而實際上,這只是個聲明。代碼中,CancellationToken 可能會被忽略。因此,有這個聲明僅僅表示方法可能支持取消,而不是一定支持。

方法對取消的響應

上面說到了,響應代碼可以響應取消,也可以不取消。

而即使響應代碼真的去響應取消,通常也會有不同的情況。

通常來說,如果取消請求到達時,響應方法實際取消了一些工作,會拋出 OperationCanceledException 來通知調用程序;而如果取消被忽略,或者取消請求來的太晚而任務已經完成,那響應方法會正常返回,而且不拋出 OperationCanceledException 異常。這個在微軟的基礎類庫(BCL)中,體現得很明顯。

大多數情況下,異常會被逐層傳出。再看一下上面的例子:

async Task SomethingAsync(int data, CancellationToken cancellationToken)
{
var result = await FirstStepAsync(data, cancellationToken);
await SecondStepAsync(intermediateValue, cancellationToken);
}

如果 FirstStepAsync 或 SecondStepAsync 拋出 OperationCanceledException,那這個異常也會從 SomethingAsync 中傳出給調用者。

這里要強調一下:看過很多代碼,在請求取消時會不拋出異常而直接返回。不要這樣做。調用者不知道這個取消是被接受,還是被忽略,會出大問題的。

一個常見的錯誤用法

在代碼 Review 時,見過好幾次這樣的情況:

async Task SomethingAsync(CancellationToken cancellationToken)
{
var test = await Task.Run(() =>
{
...
}, cancellationToken);
...
}
// 注意,這個例子的寫法是錯的。

這個有必要專門拿出來說一下。

很多人把委托和 CancellationToken 傳遞給 Task,期望在令牌取消時取消委托。注意,這個理解是錯的。

Task.Run 是對線程池的委托調度,是一個立即完成的瞬時動作。CancellationToken 在這兒的作用是取消調度這個動作,而這個動作是立即完成的,換句說說,一旦走到這一行,調度操作會立即完成,這個取消令牌也就沒有用了,會被忽略。

所以,這種情況不需要用 CancellationToken,要寫成下面的方式:

async Task SomethingAsync(CancellationToken cancellationToken)
{
var test = await Task.Run(( cancellationToken ) =>
{
...
});
...
}

寫成這樣,才是正確的表達,表達委托本身需要響應令牌。

這是一個容易搞錯的知識點,記一下。

責任編輯:武曉燕 來源: 老王Plus
相關推薦

2021-12-29 07:44:50

Dotnet 代碼系統

2021-01-20 08:16:06

異步Dotnet Core多路徑

2021-10-27 09:59:35

存儲

2024-11-05 16:58:21

RabbitMQ訂單超時取消延遲隊列

2024-10-16 09:29:30

RabbitMQ延遲隊列

2021-03-03 08:13:57

模式垃圾回收

2021-09-11 07:32:15

Java線程線程池

2010-02-24 11:19:00

Python主線程

2021-03-10 07:20:44

數據定位匹配

2021-02-03 08:12:23

函數委托Dotnet

2021-06-02 08:07:59

LinuxService應用

2021-05-26 11:30:24

Java線程池代碼

2022-09-29 09:35:56

線程池

2023-12-11 18:18:24

Python編程線程

2025-05-06 09:12:46

2011-04-20 17:15:21

并行計算

2011-04-21 09:13:14

并行計算

2021-07-07 08:01:51

命令行Dotnet Core控制臺

2021-03-17 08:12:03

架構Dotnet洋蔥

2021-09-06 10:22:47

匿名對象編程
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美在线视频网 | 国产精品爱久久久久久久 | av中文字幕在线播放 | 欧美一区视频 | 欧美一区视频 | 亚洲一av | 成人免费黄色 | 影音先锋成人资源 | 久久丁香 | 97精品超碰一区二区三区 | 玖玖国产精品视频 | 午夜在线电影网 | av一级在线观看 | 毛片视频观看 | 欧美性一区二区三区 | 91精品国产一区二区三区 | 黄色一级片在线播放 | 欧美不卡网站 | 国产精品成人一区二区三区夜夜夜 | 日韩午夜影院 | 真人毛片| 中文字幕影院 | 成人欧美一区二区三区在线播放 | 亚洲欧美激情视频 | 亚洲手机视频在线 | 欧美一区二区三区视频 | 伊人超碰| 欧美日韩18 | 国产美女视频一区 | 国产精品国产三级国产aⅴ无密码 | 视频三区| 91福利影院| 久久久久国产一区二区三区 | 自拍视频国产 | 99热这里有精品 | 美女久久久 | 国产欧美一区二区在线观看 | 自拍偷拍第一页 | 亚洲第一中文字幕 | 美女高潮网站 | 逼逼网|