自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

C#異步編程及其同步機(jī)制

開發(fā) 后端
前幾天公司內(nèi)部有人搞了一個(gè)關(guān)于多線程及其同步問題的講座,內(nèi)容很豐富,覆蓋面很廣,讓人聽了大呼過癮。他采取了橫向鋪陳的方法講的,羅列了C#下異步編程方法和模式及各種同步機(jī)制,這種講述方式對(duì)于熟悉這塊的人來說總結(jié)一下,幫助很大,但對(duì)于新手有可能就云里霧里了。雖然我研究不深,但縱向講一下這一塊內(nèi)容,對(duì)新手入門有可能會(huì)有所幫助,也算是自己對(duì)這塊內(nèi)容的一種總結(jié)。只討論技術(shù),不涉及細(xì)節(jié)和Demo。

 本篇文章涵蓋一下幾部分內(nèi)容:

    1. 什么是異步編程,為什么會(huì)需要異步編程

    2. .NET下的異步編程及其發(fā)展

    3. .NET線程同步機(jī)制及線程間數(shù)據(jù)封送

    4. 異步模式

    5. 線程安全及異常處理

    6. 線程取消

什么是異步編程,為什么會(huì)需要異步編程

           這個(gè)世界上資源是受限的。但資源限制和懶惰一樣促進(jìn)了工業(yè)和科技的發(fā)展。在計(jì)算機(jī)方面舉個(gè)例子,計(jì)算機(jī)非得是二進(jìn)制嗎?對(duì)計(jì)算機(jī)來說二進(jìn)制***嗎?不是,這是由于當(dāng)時(shí)工業(yè)水平限制,把電壓分成兩份表示0和1比分成三份更加方便且可靠;虛擬內(nèi)存管理,Cache等技術(shù)都是由當(dāng)時(shí)硬件條件所限逼出來的技術(shù),同樣異步編程和分布式編程也是。生活中的好多事物都不是線性的,拿學(xué)生時(shí)代的一個(gè)常見的例子說一下,明天開學(xué),海量作業(yè)一點(diǎn)沒寫,于是找個(gè)同學(xué)作業(yè)抄一下,但在短時(shí)間內(nèi)一個(gè)人很難抄得完,于是我花錢請(qǐng)了幾個(gè)同學(xué)一起抄,把一份工作分給幾個(gè)人去做,這就是異步了。但除去筆跡不同這么做沒有一個(gè)人抄安全,有可能哥幾個(gè)把一份內(nèi)容重復(fù)抄了好幾遍(線程安全),這期間萬一筆,紙,橡皮沒準(zhǔn)備充分還得有一個(gè)資源爭(zhēng)用,死鎖的問題(同步的問題),哥幾個(gè)抄得時(shí)候還會(huì)相互報(bào)一下各自進(jìn)度(線程間數(shù)據(jù)封送),所以說這么干是有風(fēng)險(xiǎn)的我們就得有個(gè)機(jī)制避免這種風(fēng)險(xiǎn)的發(fā)生,異步編程和這個(gè)類似。

          那在編程中異步會(huì)用在什么地方呢?一個(gè)簡(jiǎn)單情形,圖形界面程序,后臺(tái)如果要連接數(shù)據(jù)庫(kù)查詢或?qū)懭牒A繑?shù)據(jù)或者進(jìn)行I/O操作,界面會(huì)“假死”。之所以發(fā)生這種情況是這些處理都在UI線程中,這些操作占用UI線程時(shí),任何拖動(dòng)UI,點(diǎn)擊按鈕等操作都得不到及時(shí)響應(yīng)。解決的方法是將這些需要長(zhǎng)時(shí)間的操作放入一個(gè)新的線程異步操作,把UI線程解放出來。其它的應(yīng)用比如海量數(shù)據(jù)計(jì)算,服務(wù)器響應(yīng)客戶端請(qǐng)求等等。

.NET下的異步編程及其發(fā)展

         首先說明一點(diǎn),線程可以分為前臺(tái)線程和后臺(tái)線程。前臺(tái)線程和吸血鬼差不多很恐怖,要想干死進(jìn)程,就必須把所有的前臺(tái)進(jìn)程都干掉,UI線程就是前臺(tái)線程。而后臺(tái)線程就是二房生的兒子了,進(jìn)程消亡后緊跟著死掉了,很明顯的后臺(tái)線程就是Word的拼寫檢查,或者outlook負(fù)責(zé)跟服務(wù)器同步更新郵件的線程。

        任何平臺(tái)和編程語言都會(huì)有多線程的實(shí)現(xiàn)機(jī)制和方法。對(duì)于C#來講Thread類就是創(chuàng)建線程,管理線程的一種最初始的手段。但是創(chuàng)建和銷毀一個(gè)線程是很耗費(fèi)資源的,而且創(chuàng)建的線程越多,線程間切換就越頻繁(計(jì)算機(jī)CPU個(gè)數(shù)受限),線程切換也要耗費(fèi)資源和時(shí)間,再加上線程管理是一件很費(fèi)心的事,所以微軟就引入了線程池的概念。線程池是一個(gè)先進(jìn)先出FIFO的隊(duì)列,程序員只需要把操作或者任務(wù)丟給線程池,讓.NET framework替程序員管理線程,線程復(fù)用等,極大的簡(jiǎn)化了開發(fā)。這里就有一個(gè)控制線程池內(nèi)線程數(shù)量的問題。線程池內(nèi)的線程肯定得根據(jù)需要?jiǎng)討B(tài)變化,但適應(yīng)這種需要的算法是什么呢?

          一個(gè)簡(jiǎn)單的算法:往線程池中增加一些線程,觀察線程池的吞吐量,如果增加后吞吐量增加,說明線程不夠,需要增加線程。但這存在一個(gè)問題,對(duì)于一個(gè)很大的任務(wù)需要長(zhǎng)時(shí)間占用線程,增加線程并不能增加吞吐量,此時(shí)如果增加線程會(huì)加重負(fù)擔(dān)。所以在CLR v4時(shí)引入了本地隊(duì)列(Local  Queue)的概念,如果一個(gè)線程內(nèi)創(chuàng)建了另一個(gè)線程,新創(chuàng)建的線程不再丟給全局隊(duì)列,而是給本地隊(duì)列排隊(duì)等候調(diào)用。這就又有個(gè)問題,如果一個(gè)隊(duì)列內(nèi)任務(wù)執(zhí)行完了,而另一個(gè)隊(duì)列還有好多怎么辦?那就讓執(zhí)行完任務(wù)的本地隊(duì)列從該隊(duì)列上“偷“一個(gè)線程執(zhí)行。這樣達(dá)到負(fù)載均衡。當(dāng)然線程池的算法會(huì)隨著CLR版本升級(jí)而不斷演進(jìn),更加智能的管理線程。對(duì)普通開發(fā)者而言可以不用考慮這些細(xì)節(jié),無縫的體驗(yàn)線程池帶來的便利和效率就行了。                   

       線程池如此方便,我們?cè)趺词褂镁€程池呢?可以通過以下幾種方式:

通過類方法ThreadPool.QueueUserWorkItem直接調(diào)用。

通過.net Framework 4.0 引入的TPL(Task Parallel Library)任務(wù)并行庫(kù)。

         TPL中最主要的兩個(gè)類是Task和Parallel。而新版C++標(biāo)準(zhǔn)中也引入了類似的概念parallel_for, parallel_foreach, parallel_invoke等。

         詳細(xì)信息見以下鏈接。

通過異步委托(BeginInvoke/EndInvoke)調(diào)用。

通過BackgroundWorker, BackgroundWorker是WinForm, WPF下的一個(gè)控件,主要用于提供UI控件下的協(xié)作式取消,進(jìn)度報(bào)告等。

        這里我還要講一下PFX(Parallel FrameWork)。PFX從概念上可以分為數(shù)據(jù)并行和任務(wù)并行。

上層的由兩個(gè)結(jié)構(gòu)化數(shù)據(jù)并行APIs組成:PLINQ和Parallel類。而底層的任務(wù)并行包含了Task 類和一系列的附屬結(jié)構(gòu)用于幫助并行編程。注意PFX是建立在線程池之上的,是更好使用線程池的一種途徑,有說法說是用TPL比直接使用線程池效率更高。關(guān)于PLINQ,Task,Parallel類及上圖所列結(jié)構(gòu)的使用請(qǐng)參考一下鏈接。

.NET線程同步機(jī)制及線程間數(shù)據(jù)封送

        首先.Net的同步機(jī)制是干什么的?概況來講是為了安全。同步機(jī)制的存在是因?yàn)楫惒讲僮魇遣话踩模瑫?huì)帶來一系列的問題,這些問題在***章節(jié)中已經(jīng)討論過了。而線程間數(shù)據(jù)封送和COM與.Net framework數(shù)據(jù)封送一樣,是為了線程間數(shù)據(jù)和狀態(tài)的傳遞。

那么.net的同步機(jī)制有哪些呢?概括一下:

  1.   簡(jiǎn)單的鎖定方法:Thead類的Sleep, Join等以及Task的Wait方法。

  2.   基于對(duì)象的鎖定:

                 lock(Monitor.Enter/Monitor.Exit):首先強(qiáng)調(diào)一下它不可以跨進(jìn)程間線程同步。一般跨進(jìn)間線程同步都有一個(gè)特征,就是同步對(duì)象都有名字。

                 Mutex和Semophore(slim):這兩個(gè)都可以跨進(jìn)程同步,兩者的區(qū)別在于:Mutex只能有一等待資源,而Semophore可以有多個(gè)。拿廁所舉例,Mutex相當(dāng)于廁所中只有一個(gè)蹲位,只能一個(gè)上了才能上另一個(gè),而Semophore可以有多個(gè)蹲位,可以讓多個(gè)線程同時(shí)阻塞一個(gè)線程的執(zhí)行。就是n個(gè)哥們一起蹲著,又來一哥們,然后這n個(gè)哥們就占著那啥不那啥。

                 Reade/Writer 鎖。

     3.基于信號(hào)

                事件等待句柄AutoResetEvent, ManualResetEvent(Slim):注意這兩個(gè)也是允許跨進(jìn)程的,兩者用法差不多,使一個(gè)線程釋放一個(gè)信號(hào)從而使得其他線程能夠執(zhí)行。

                CountdownEvent(4.0被引入):這個(gè)和上邊用法正好相反,它使得一個(gè)線程等待收到其他線程的信號(hào)后再執(zhí)行。

                Barrier

                Wait and pulse

     4. 非阻塞的同步結(jié)構(gòu)

                Thread.MemoryBarrier

                Thread.VolatileRead/Write

                Interlocaked   

  關(guān)于以上同步機(jī)制具體應(yīng)用和Demo代碼請(qǐng)參考以下鏈接。

  而關(guān)于線程間數(shù)據(jù)封送,一個(gè)很好的例子就是點(diǎn)擊button后開始在新線程中執(zhí)行某個(gè)操作,但執(zhí)行過程需要在一個(gè)label上顯示出來,這時(shí)候就需要把新線程內(nèi)表示執(zhí)行狀態(tài)的數(shù)據(jù)對(duì)象封送回UI線程。這部分內(nèi)容可以參考我以前寫的一篇帖子:http://www.cnblogs.com/salomon/archive/2012/06/28/2567339.html。                        

異步模式

    什么需要異步模式?所謂模式,其實(shí)是一種方法,就跟上篇博客里所講的,是從工程實(shí)踐中總結(jié)出來的解決相似或特定問題的一種慣用手段。常見的異步模式包括:

      APM模式: BeginXXX/EndXXX, IAsyncResult

      EAP模式(基于事件的異步模式)

           Windows Form

           MethodNameAsync

           Event

     TAP(基于任務(wù)的異步模式)

           MethodNameAsync

           Task/Task<Result>

     這部分內(nèi)容以下鏈接講得很好了,感興趣可以看一下。更詳盡的介紹去MSDN或者官方網(wǎng)站上去找相似的文檔。

線程安全及異常處理

   新線程中拋出的異常會(huì)不會(huì)自動(dòng)封送到主線程中?如何處理新線程中拋出的異常?什么是線程安全?怎樣做到線程安全?

線程取消

   正在執(zhí)行的線程怎么能不能取消,怎么取消合適?暴力取消?協(xié)作式取消?

C#5.0新的異步模式Async和await關(guān)鍵字

   請(qǐng)參考我以前的博客:http://www.cnblogs.com/salomon/archive/2012/06/27/2565862.html

原文鏈接:http://www.cnblogs.com/salomon/archive/2012/07/26/2610548.html

【編輯推薦】

  1. C#、LINQ與ADO.NET主從表比對(duì)操作
  2. C#幾個(gè)經(jīng)常犯錯(cuò)誤匯總
  3. C#開發(fā)高性能Log Help類設(shè)計(jì)開發(fā)
  4. C#使用委托調(diào)用實(shí)現(xiàn)用戶端等待閃屏
  5. 淺談C#結(jié)構(gòu)

責(zé)任編輯:彭凡 來源: 博客園
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)