C 非同步程式設計入門看這篇就夠了

2021-10-09 13:34:06 字數 3651 閱讀 7123

隨著.net core的流行,相信你現在的**中或多或少的會用到async以及await吧!畢竟已成標配。那麼我們為什麼要用async以及await呢?其實這是微軟團隊為我們提供的乙個語法糖,讓我們不用996就可以輕鬆的編寫非同步**,並無太過神奇的地方。那麼,問題來了,什麼是非同步?非同步到底又是怎樣的乙個過程呢?

在開始講非同步前我們先從乙個生活中的小故事說起吧。話說2023年12月15日週日這一天有位程式猿小祝在這天居然沒有加班,選擇在家休息了,然後他習慣性的用microsoft to do羅列了一下這天要做的事情,如下圖所示:

這一天這個程式猿小祝計畫早上九點起床洗澡,然後吃早餐,洗衣服,分享一篇關於c#非同步相關的文章,晚上在家加下班~~沒錯,這個苦逼休息的時候也得工作,不然下週的任務有可能完不成要挨批了。

當然,這個程式猿小祝卻採用了另一種方式來進行:起床後先把衣服換下來用洗衣機洗了,然後開始洗澡,然後吃飯,寫了一會文章,然後等衣服洗好後再把衣服給晾好繼續回來寫文章,最後在晚上的時候遠端寫**。在這個過程中這個程式猿在洗衣服的同時就去洗澡,吃飯寫了會文章了,這個過程就是乙個非同步的過程。

可能這個故事比喻的不恰當,不過大夥將就著看下吧,總結一下同步跟非同步吧:

非同步方法:可以在尚未完成所有指令的時候提前返回(如上面的洗衣服過程沒執行完就返回去洗澡了),等到該方法等候的那項任務執行完畢後,在令這個方法從早前還沒執行完的那個地方繼續往下執行(如:衣服洗好晾好後,繼續寫文章了)。

下面我們結合偽**來進行更加詳細的講解吧。

這一節我們就用偽**來分別實現下同步過程及非同步過程吧。

同步過程

下面我們用偽**來實現上述故事中的過程吧。

static void main(string args)

秒!", stopwatch.elapsedmilliseconds/1000);

console.readkey();

}private static void bash()

private static void breakfast()

private static void washclothes()

private static void writearticle()

private static void writingcode()

上面的**沒什麼難的,寫完**後我們直接dotnet run一下**,如下圖所示:

我們可以看到這個**的執行過程是嚴格按照我們編碼的順序執行的,即同步執行的**。這裡用時共40秒!

非同步過程

我們只需要稍微改造下使得**非同步執行再來看下效果吧!偽**如下:

static async task main(string args)

;tasks.add(breakfast());//吃早餐

tasks.add(washclothes());//洗衣服

tasks.add(writearticle());//寫文章

tasks.add(writingcode());//寫**

await task.whenall(tasks);

console.writeline("main非同步演示結束~~~~~共用時秒!", stopwatch.elapsedmilliseconds/1000);

console.readkey();

}private static async task bash()

private static async task breakfast()

private static async task washclothes()

private static async task writearticle()

private static async task writingcode()

然後我們再直接dotnet run一下**,如下圖所示:

我們可以看到這個**的執行過程中遇到await後就會返回執行了,待await的**執行完畢後才繼續執行接下來的**的!為了避免有的讀者看不懂,我簡單分析其中乙個方法的執行過程吧。具體的還需要你自己把非同步**拷貝下來,多打幾個斷點,然後把等待時間*100(時間長點方便我們檢視斷點的進入順序,否則時間短,還沒來得及進斷點可能**已經執行完了)看看斷點的進入步驟吧!

我也只列了一部分,具體的你們自行打斷點看下吧。

編譯器在處理非同步方法的時候,會構建一種機制,該機制可以啟動await語句所要等候的那項非同步任務,並使得程式在該工作完成之後,能夠用某個執行緒繼續執行await語句後面的那些**。這個await語句正是關鍵所在。編譯器會構建相應的資料結構,並把await之後的指令表示成delegate,使得程式在處理完那項非同步任務之後,能夠繼續執行下面的那些指令。編譯器會把當前方法中的每乙個區域性變數的值都儲存在這個資料結構中,並根據await語句所要等候的任務來配置相應的邏輯,讓程式能夠在該任務完成之後指派某個執行緒,從await語句的下一條指令開始繼續執行。實際上,這相當於編譯器生成了乙個delegate,用以表示await語句之後的那些**,並寫入了相應的狀態資訊,用以確保await語句所等候的那項任務執行完畢以後這個delegate能夠正確的得到呼叫。

這使得該方法看上去好像是從早前暫停的地方繼續往下執行了,也就是所,系統會把狀態恢復到早前暫停的樣式,並且直接把程式中的某個執行緒放到適當的語句上,令其能夠繼續向下執行。

這個過程實際上是由synchronizationcontext類來實現的,該類用來保證非同步方法能夠在它所等候的任務執行完畢時,從早前停下來的地方繼續往下執行,並確保該方法此時所處的環境與上下文能夠與當初的情況一樣。

通過上面的講述我們可以知道通過asyncawait關鍵字寫出來的非同步方法並沒有太過神奇的地方。只不過編譯器會針對這種方法生成許多**,使得呼叫這個方法的主調方無需等待該方法完工,就可以繼續往下執行,並確保該方法所等候的那項任務在執行過程中發生的錯誤能夠適當的得到回報。這樣的好處是,如果非同步方法執行到await語句時它所要等候的那項任務還沒有完成,那麼該方法的執行進度就會暫停在那裡,直到那項任務完成之後,才回繼續往下執行。

《more effective c#》機械工業出版社

依樂祝自己的理解

入門Webpack,看這篇就夠了

參見 需要注意的是 1.npm install g webpack 全域性安裝 2.npm init 建立package.json 3.建立webpack.config.js 4.因為是全域性安裝,所以打包檔案只需在終端執行 webpack 命令 我之前的錯誤之處在於我是先全域性安裝的,然後又按照文...

Python開發入門,看這篇就夠了!

python簡介 當前python應用相當廣泛,常見的有後端開發 軟體開發 web開發 人工智慧 網路爬蟲,尤其是爬蟲技術 大資料技術,可謂是盡人皆知了。開發工具 python有兩個不同的大版本,乙個是2.x版,乙個是3.x版,這兩個版本是不相容的。當然版本越高表明功能越強大,效能越穩定,所以建議還...

Dockerfile看這篇就夠了

dockerfile是用來構建docker映象的構建檔案,是由一系列命令和引數構成的指令碼。構建三步驟 1.編寫dockerfile檔案 2.docker build 3.docker run 1 每條保留字指令都必須為大寫字母且後面要跟隨至少乙個引數 2 指令按照從上到下,順序執行 3 表示注釋 ...