淺說非同步程式設計

2022-03-07 17:15:31 字數 4053 閱讀 2821

非同步程式設計從很久之前就開始學習,但是發現只要是不總結的東西,總是特別容易忘記,而且沒有深入的學習和實踐,對技術的細節和原理也是理解不深,所以這次一定要把最新學到的,和原來記憶不清的知識從新梳理一遍。

執行緒,程序和應用程式域的基本知識在這有總結:

同步非同步和阻塞非阻塞,有簡單理解也有詳細解釋,同時對應到linux的五種網路模型,這裡簡單解釋一下:

「阻塞」與"非阻塞"與"同步"與「非同步"不能簡單的從字面理解,提供乙個從分布式系統角度的回答。

1.同步與非同步:同步和非同步關注的是訊息通訊機制(synchronous

communication/ asynchronous communication)所謂同步,就是在發出乙個呼叫時,在沒有得到結果之前,該呼叫就不返回。但是一旦呼叫返回,就得到返回值了。

換句話說,就是由呼叫者主動等待這個呼叫的結果。而非同步則是相反,呼叫在發出之後,這個呼叫就直接返回了,所以沒有返回結果。換句話說,當乙個非同步過程呼叫發出後,呼叫者不會立刻得到結果。而是在呼叫發出後,被呼叫者通過狀態、通知來通知呼叫者,或通過**函式處理這個呼叫。

典型的非同步程式設計模型比如node.js舉個通俗的例子:你打**問書店老闆有沒有《分布式系統》這本書,如果是同步通訊機制,書店老闆會說,你稍等,」我查一下",然後開始查啊查,等查好了(可能是5秒,也可能是一天)告訴你結果(返回結果)。而非同步通訊機制,書店老闆直接告訴你我查一下啊,查好了打**給你,然後直接掛**了(不返回結果)。然後查好了,他會主動打**給你。在這裡老闆通過「回電」這種方式來**。

2.阻塞與非阻塞阻塞和非阻塞關注的是程式在等待呼叫結果(訊息,返回值)時的狀態.阻塞呼叫是指呼叫結果返回之前,當前執行緒會被掛起。呼叫執行緒只有在得到結果之後才會返回。非阻塞呼叫指在不能立刻得到結果之前,該呼叫不會阻塞當前執行緒。

在我的理解中,.net的非同步程式比較舊的有手動建立thread,非同步的委託呼叫。到了.net framwork 4.5以後,有了async和await,相對於原始的非同步程式設計,變得更加簡潔和易讀,但是要完全搞懂還是需要深入學習一下。

static void main(string args)

", thread.currentthread.managedthreadid);

printer p = new printer();

waitcallback workitem = new waitcallback(printnumbers);

for (int i = 0; i < 10; i++)

console.readline();

}static void printnumbers(object state)

waitcallback 委託指向有單個object型別的引數且無返回值的方法。

threadpool.queueuserworkitem()方法使用執行緒池中的工作者執行緒排隊執行乙個方法。

使用執行緒池的好處主要是:

在某些情況下我們還是有限使用手動執行緒管理:

(以上內容大多是抄書,還沒有在專案中有深刻的體會,以後再補充)

task 的內容和後面的async、await關係比較密切,就多查了一下資料,內容很多,只能慢慢寫。

大綱:

task和taskfactory

start,run,wait,waitall,wenall

錯誤捕捉

強制停止

2.2.1 task初始化

建立task有三種方式:

task t1=new task(mymethod);

task t2= task.factory.startnew(mymethod);

task t3=task.run(mymethod);

msdn說處於效能考慮,推薦使用後兩種方式。而且後兩種方式不需要手動start()

2.2.2 start、run、wait、waitall、wenall

有幾個比較重要的方法,摘抄一下msdn的定義。

2.2.3 異常處理

在非同步程式設計中,主線程是無法捕獲工作者執行緒丟擲的exception,目前處理異常有兩種思路,一種是用continuewith()在下乙個task處理異常,另一種是包裝到主線程,由主線程處理。

下面是使用contiuewith()

static void main(string args)

發生錯誤");

});t1.start();

task t2 = t1.continuewith((task) =>

});console.readkey();

}

使用await包裝到主線程處理:

static void main(string args)  

);

t.start();

task ttend = t.continuewith((task) =>

, taskcontinuationoptions.onlyonfaulted);

try

catch (aggregateexception err)

來自:

異常內容:", item.innerexception.gettype(),

environment.newline, item.innerexception.source,

environment.newline, item.innerexception.message);

} }

console.writeline("主線程馬上結束");

console.readkey();

}

使用事件通知包裝到主線程:

static event eventhandleraggregateexceptioncatched;  

public class aggregateexceptionargs: eventargs

} static void main(string args)

catch (exception err)

; aggregateexceptioncatched(null, errargs);

} });

t.start();

console.writeline("主線程馬上結束");

console.readkey();

} static void program_aggregateexceptioncatched(object sender, aggregateexceptionargs e)

來自:異常內容:",

item.gettype(), environment.newline, item.source,

environment.newline, item.message);

} }

大綱:

3.1.1 概念和簡介

3.1.2 使用示例

微軟msdn上的執行順序圖。

class program

private static async taskgetlengthasync()

private static taskgetstringasync());}

}

測試**執行結果為:

下面是個人的理解,如果用await 標記等待非同步方法,那麼這裡就是非同步阻塞的,如果用task物件去接受非同步方法返回的task,就是非同步非阻塞的,而且真正的非同步**,基本上是在task.run()內部才開始真正在其他執行緒上執行。

3.1.3 專案實戰

專案中我要實現的是乙個多執行緒爬蟲,尤其是在每個站點的列表頁爬取完成後,需要爬取20-30個詳情頁,目前只做了詳情頁的多執行緒。

3.1.4 原理

執行的原理其實是task+狀態機。這裡就不詳細研究了,貼上一下學習時用到的鏈結。

發散思維淺說

在策劃乙個系統的時候,我們往往發現人類對縝密思考還有很長的路要走。本身也是若干簡單而成熟的技術組成的系統,總要不斷的修正,再想想,再看看,再研究研究,在比較比較,再參詳參詳,再考慮考慮 大俠並非自詡什麼邏輯學專家,這裡只是簡單對發散思維做一些淺述,希望對新手和即將步入大學的弟妹們有個好的啟蒙 對於嚴...

網路 DNS淺說

一般普通的撥號使用者當撥號成功後,會自動獲得運營商分配的ip和dns伺服器位址,一般不需要我們手動設定 而專線使用者由於是固定ip,如果只設定了ip位址,是無法發開網頁的,必須手工進行設定,如果使用路由器了,最好在路由器裡面設定。一般情況dns是不需要我們自己配置的,只有特定的情況才會去配置,下面列...

淺說預解析

全域性作用域 當瀏覽器載入html頁面的時候,首先會提供乙個全域性js 執行的環境.這個環境就是全域性作用域 window var num 12 var obj function fn fn 預解析 在當前作用域中,js 執行之前瀏覽器首先會預設把所有帶var和function的進行提前的宣告或者定...