久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長(zhǎng)資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      go語(yǔ)言中并發(fā)圖文教程

      go語(yǔ)言中并發(fā)圖文教程

      正如過(guò)程式編程和面向?qū)ο笠粯?,一個(gè)好的編程模式需要有一個(gè)極其簡(jiǎn)潔的內(nèi)核,還有在此之上豐富的外延,可以解決現(xiàn)實(shí)世界中各種各樣的問(wèn)題。本文以GO語(yǔ)言為例,解釋其中內(nèi)核、外延。

      并發(fā)模式之內(nèi)核

      這種并發(fā)模式的內(nèi)核只需要協(xié)程和通道就夠了。其中協(xié)程負(fù)責(zé)執(zhí)行代碼,通道負(fù)責(zé)在協(xié)程之間傳遞事件。

      go語(yǔ)言中并發(fā)圖文教程

      并發(fā)編程一直以來(lái)都是個(gè)非常困難的工作。要想編寫(xiě)一個(gè)良好的并發(fā)程序,我們不得不了解線程, 鎖,semaphore,barrier甚至CPU更新高速緩存的方式,而且他們個(gè)個(gè)都有怪脾氣,處處是陷阱。筆者除非萬(wàn)不得以,決不會(huì)自己操作這些底層 并發(fā)元素。一個(gè)簡(jiǎn)潔的并發(fā)模式不需要這些復(fù)雜的底層元素,只需協(xié)程和通道就夠了。

      協(xié)程是輕量級(jí)的線程。在過(guò)程式編程中,當(dāng)調(diào)用一個(gè)過(guò)程的時(shí)候,需要等待其執(zhí)行完才返回。而調(diào)用一個(gè)協(xié)程的時(shí)候,不需要等待其執(zhí)行完,會(huì)立即返回。

      協(xié)程十分輕量,Go語(yǔ)言可以在一個(gè)進(jìn)程中執(zhí)行有數(shù)以十萬(wàn)計(jì)的協(xié)程,依舊保持高性能。而對(duì)于普通的平臺(tái),一個(gè)進(jìn)程有數(shù)千個(gè)線程,其CPU會(huì)忙于上下文切換,性能急劇下降。隨意創(chuàng)建線程可不是一個(gè)好主意,但是我們可以大量使用的協(xié)程。

      通道是協(xié)程之間的數(shù)據(jù)傳輸通道。通道可以在眾多的協(xié)程之間傳遞數(shù)據(jù),具體可以值也可以是個(gè)引用。通道有兩種使用方式。

      協(xié)程可以試圖向通道放入數(shù)據(jù),如果通道滿(mǎn)了,會(huì)掛起協(xié)程,直到通道可以為他放入數(shù)據(jù)為止。

      協(xié)程可以試圖向通道索取數(shù)據(jù),如果通道沒(méi)有數(shù)據(jù),會(huì)掛起協(xié)程,直到通道返回?cái)?shù)據(jù)為止。

      如此,通道就可以在傳遞數(shù)據(jù)的同時(shí),控制協(xié)程的運(yùn)行。有點(diǎn)像事件驅(qū)動(dòng),也有點(diǎn)像阻塞隊(duì)列。這兩個(gè)概念非常的簡(jiǎn)單,各個(gè)語(yǔ)言平臺(tái)都會(huì)有相應(yīng)的實(shí)現(xiàn)。在Java和C上也各有庫(kù)可以實(shí)現(xiàn)兩者。

      go語(yǔ)言中并發(fā)圖文教程

      只要有協(xié)程和通道,就可以?xún)?yōu)雅的解決并發(fā)的問(wèn)題。不必使用其他和并發(fā)有關(guān)的概念。那如何用這兩把利刃解決各式各樣的實(shí)際問(wèn)題呢?

      并發(fā)模式之外延

      協(xié)程相較于線程,可以大量創(chuàng)建。打開(kāi)這扇門(mén),我們拓展出新的用法,可以做生成器,可以讓函數(shù)返回“服務(wù)”,可以讓循環(huán)并發(fā)執(zhí)行,還能共享變量。但是出現(xiàn)新 的用法的同時(shí),也帶來(lái)了新的棘手問(wèn)題,協(xié)程也會(huì)泄漏,不恰當(dāng)?shù)氖褂脮?huì)影響性能。下面會(huì)逐一介紹各種用法和問(wèn)題。演示的代碼用GO語(yǔ)言寫(xiě)成,因?yàn)槠浜?jiǎn)潔明 了,而且支持全部功能。

      1、生成器

      有的時(shí)候,我們需要有一個(gè)函數(shù)能不斷生成數(shù)據(jù)。比方說(shuō)這個(gè)函數(shù)可以讀文件,讀網(wǎng)絡(luò),生成自增長(zhǎng)序列,生成隨機(jī)數(shù)。這些行為的特點(diǎn)就是,函數(shù)的已知一些變量,如文件路徑。然后不斷調(diào)用,返回新的數(shù)據(jù)。

      go語(yǔ)言中并發(fā)圖文教程

      下面生成隨機(jī)數(shù)為例,以讓我們做一個(gè)會(huì)并發(fā)執(zhí)行的隨機(jī)數(shù)生成器。

      // 函數(shù)rand_generator_1 ,返回 int funcrand_generator_1() int {          return rand.Int() } //        上面是一個(gè)函數(shù),返回一個(gè)int。假如rand.Int()這個(gè)函數(shù)調(diào)用需要很長(zhǎng)時(shí)間等待,那該函數(shù)的調(diào)用者也會(huì)因此而掛起。所以我們可以創(chuàng)建一個(gè)協(xié)程,專(zhuān)門(mén)執(zhí)行rand.Int()。   // 函數(shù)rand_generator_2,返回通道(Channel) funcrand_generator_2() chan int {          // 創(chuàng)建通道          out := make(chan int)          // 創(chuàng)建協(xié)程          go func() {                   for {                            //向通道內(nèi)寫(xiě)入數(shù)據(jù),如果無(wú)人讀取會(huì)等待                             out <- rand.Int()                    }          }()          return out }  funcmain() {          // 生成隨機(jī)數(shù)作為一個(gè)服務(wù)          rand_service_handler :=rand_generator_2()          // 從服務(wù)中讀取隨機(jī)數(shù)并打印          fmt.Printf("%dn",<-rand_service_handler) }

      上面的這段函數(shù)就可以并發(fā)執(zhí)行了rand.Int()。有一點(diǎn)值得注意到函數(shù)的返回可以理解為一個(gè)“服務(wù)”。但我們需要獲取隨機(jī)數(shù)據(jù)時(shí)候,可以隨時(shí)向這個(gè) 服務(wù)取用,他已經(jīng)為我們準(zhǔn)備好了相應(yīng)的數(shù)據(jù),無(wú)需等待,隨要隨到。

      如果我們調(diào)用這個(gè)服務(wù)不是很頻繁,一個(gè)協(xié)程足夠滿(mǎn)足我們的需求了。但如果我們需要大量訪問(wèn),怎么辦?我們可以用下面介紹的多路復(fù)用技術(shù),啟動(dòng)若干生成器,再將其整合成一個(gè)大的服務(wù)。

      調(diào)用生成器,可以返回一個(gè)“服務(wù)”??梢杂迷诔掷m(xù)獲取數(shù)據(jù)的場(chǎng)合。用途很廣泛,讀取數(shù)據(jù),生成ID,甚至定時(shí)器。這是一種非常簡(jiǎn)潔的思路,將程 序并發(fā)化。

      2、多路復(fù)用

      多路復(fù)用是讓一次處理多個(gè)隊(duì)列的技術(shù)。Apache使用處理每個(gè)連接都需要一個(gè)進(jìn)程,所以其并發(fā)性能不是很好。而Nginx使用多路復(fù)用的技術(shù),讓一 個(gè)進(jìn)程處理多個(gè)連接,所以并發(fā)性能比較好。

      同樣,在協(xié)程的場(chǎng)合,多路復(fù)用也是需要的,但又有所不同。多路復(fù)用可以將若干個(gè)相似的小服務(wù)整合成一個(gè)大服務(wù)。

      go語(yǔ)言中并發(fā)圖文教程

      那么讓我們用多路復(fù)用技術(shù)做一個(gè)更高并發(fā)的隨機(jī)數(shù)生成器吧。

      // 函數(shù)rand_generator_3 ,返回通道(Channel)          funcrand_generator_3() chan int {          // 創(chuàng)建兩個(gè)隨機(jī)數(shù)生成器服務(wù)          rand_generator_1 := rand_generator_2()          rand_generator_2 := rand_generator_2()          //創(chuàng)建通道          out := make(chan int)           //創(chuàng)建協(xié)程          go func() {                    for {                            //讀取生成器1中的數(shù)據(jù),整合                            out <-<-rand_generator_1                    }          }()          go func() {                    for {                             //讀取生成器2中的數(shù)據(jù),整合                             out <-<-rand_generator_2                    }          }()          return out }

      上面是使用了多路復(fù)用技術(shù)的高并發(fā)版的隨機(jī)數(shù)生成器。通過(guò)整合兩個(gè)隨機(jī)數(shù)生成器,這個(gè)版本的能力是剛才的兩倍。雖然協(xié)程可以大量創(chuàng)建,但是眾多協(xié)程還是會(huì)爭(zhēng)搶輸出的通道。

      Go語(yǔ)言提供了Select關(guān)鍵字來(lái)解決,各家也有各家竅門(mén)。加大輸出通道的緩沖大小是個(gè)通用的解決方法。

      多路復(fù)用技術(shù)可以用來(lái)整合多個(gè)通道。提升性能和操作的便捷。配合其他的模式使用有很大的威力。

      3、Future技術(shù)

      Future是一個(gè)很有用的技術(shù),我們常常使用Future來(lái)操作線程。我們可以在使用線程的時(shí)候,可以創(chuàng)建一個(gè)線程,返回Future,之后可以通過(guò)它等待結(jié)果。 但是在協(xié)程環(huán)境下的Future可以更加徹底,輸入?yún)?shù)同樣可以是Future的。

      go語(yǔ)言中并發(fā)圖文教程

      調(diào)用一個(gè)函數(shù)的時(shí)候,往往是參數(shù)已經(jīng)準(zhǔn)備好了。調(diào)用協(xié)程的時(shí)候也同樣如此。但是如果我們將傳入的參 數(shù)設(shè)為通道,這樣我們就可以在不準(zhǔn)備好參數(shù)的情況下調(diào)用函數(shù)。這樣的設(shè)計(jì)可以提供很大的自由度和并發(fā)度。函數(shù)調(diào)用和函數(shù)參數(shù)準(zhǔn)備這兩個(gè)過(guò)程可以完全解耦。 下面舉一個(gè)用該技術(shù)訪問(wèn)數(shù)據(jù)庫(kù)的例子。

      //一個(gè)查詢(xún)結(jié)構(gòu)體 typequery struct {          //參數(shù)Channel          sql chan string          //結(jié)果Channel          result chan string } //執(zhí)行Query funcexecQuery(q query) {          //啟動(dòng)協(xié)程          go func() {                    //獲取輸入                    sql := <-q.sql                    //訪問(wèn)數(shù)據(jù)庫(kù),輸出結(jié)果通道                    q.result <- "get" + sql          }() } funcmain() {          //初始化Query          q :=                    query{make(chan string, 1),make(chan string, 1)}          //執(zhí)行Query,注意執(zhí)行的時(shí)候無(wú)需準(zhǔn)備參數(shù)          execQuery(q)          //準(zhǔn)備參數(shù)          q.sql <- "select * fromtable"          //獲取結(jié)果          fmt.Println(<-q.result) }

      上面利用Future技術(shù),不單讓結(jié)果在Future獲得,參數(shù)也是在Future獲取。準(zhǔn)備好參數(shù)后,自動(dòng)執(zhí)行。Future和生成器的區(qū)別在 于,F(xiàn)uture返回一個(gè)結(jié)果,而生成器可以重復(fù)調(diào)用。還有一個(gè)值得注意的地方,就是將參數(shù)Channel和結(jié)果Channel定義在一個(gè)結(jié)構(gòu)體里面作為 參數(shù),而不是返回結(jié)果Channel。這樣做可以增加聚合度,好處就是可以和多路復(fù)用技術(shù)結(jié)合起來(lái)使用。

      Future技術(shù)可以和各個(gè)其他技術(shù)組合起來(lái)用??梢酝ㄟ^(guò)多路復(fù)用技術(shù),監(jiān)聽(tīng)多個(gè)結(jié)果Channel,當(dāng)有結(jié)果后,自動(dòng)返回。也可以和生成器組合使用,生 成器不斷生產(chǎn)數(shù)據(jù),F(xiàn)uture技術(shù)逐個(gè)處理數(shù)據(jù)。Future技術(shù)自身還可以首尾相連,形成一個(gè)并發(fā)的pipe filter。這個(gè)pipe filter可以用于讀寫(xiě)數(shù)據(jù)流,操作數(shù)據(jù)流。

      Future是一個(gè)非常強(qiáng)大的技術(shù)手段??梢栽谡{(diào)用的時(shí)候不關(guān)心數(shù)據(jù)是否準(zhǔn)備好,返回值是否計(jì)算好的問(wèn)題。讓程序中的組件在準(zhǔn)備好數(shù)據(jù)的時(shí)候自動(dòng)跑起來(lái)。

      4、并發(fā)循環(huán)

      循環(huán)往往是性能上的熱點(diǎn)。如果性能瓶頸出現(xiàn)在CPU上的話,那么九成可能性熱點(diǎn)是在一個(gè)循環(huán)體內(nèi)部。所以如果能讓循環(huán)體并發(fā)執(zhí)行,那么性能就會(huì)提高很多。

      go語(yǔ)言中并發(fā)圖文教程

      要并發(fā)循環(huán)很簡(jiǎn)單,只有在每個(gè)循環(huán)體內(nèi)部啟動(dòng)協(xié)程。協(xié)程作為循環(huán)體可以并發(fā)執(zhí)行。調(diào)用啟動(dòng)前設(shè)置一個(gè)計(jì)數(shù)器,每一個(gè)循環(huán)體執(zhí)行完畢就在計(jì)數(shù)器上加一個(gè)元素,調(diào)用完成后通過(guò)監(jiān)聽(tīng)計(jì)數(shù)器等待循環(huán)協(xié)程全部完成。

      //建立計(jì)數(shù)器 sem :=make(chan int, N); //FOR循環(huán)體 for i,xi:= range data {          //建立協(xié)程     go func (i int, xi float) {         doSomething(i,xi);                    //計(jì)數(shù)         sem <- 0;     } (i, xi); } // 等待循環(huán)結(jié)束 for i := 0; i < N; ++i {  <-sem }

      上面是一個(gè)并發(fā)循環(huán)例子。通過(guò)計(jì)數(shù)器來(lái)等待循環(huán)全部完成。如果結(jié)合上面提到的Future技術(shù)的話,則不必等待??梢缘鹊秸嬲枰慕Y(jié)果的地方,再去檢查數(shù)據(jù)是否完成。

      通過(guò)并發(fā)循環(huán)可以提供性能,利用多核,解決CPU熱點(diǎn)。正因?yàn)閰f(xié)程可以大量創(chuàng)建,才能在循環(huán)體中如此使用,如果是使用線程的話,就需要引入線程池之類(lèi)的東西,防止創(chuàng)建過(guò)多線程,而協(xié)程則簡(jiǎn)單的多。

      5、ChainFilter技術(shù)

      前面提到了Future技術(shù)首尾相連,可以形成一個(gè)并發(fā)的pipe filter。這種方式可以做很多事情,如果每個(gè)Filter都由同一個(gè)函數(shù)組成,還可以有一種簡(jiǎn)單的辦法把他們連起來(lái)。

      go語(yǔ)言中并發(fā)圖文教程

      由于每個(gè)Filter協(xié)程都可以并發(fā)運(yùn)行,這樣的結(jié)構(gòu)非常有利于多核環(huán)境。下面是一個(gè)例子,用這種模式來(lái)產(chǎn)生素?cái)?shù)。

      // Aconcurrent prime sieve packagemain // Sendthe sequence 2, 3, 4, ... to channel 'ch'. funcGenerate(ch chan<- int) {          for i := 2; ; i++ {                   ch<- i // Send 'i' to channel 'ch'.          } } // Copythe values from channel 'in' to channel 'out', //removing those divisible by 'prime'. funcFilter(in <-chan int, out chan<- int, prime int) {          for {                    i := <-in // Receive valuefrom 'in'.                    if i%prime != 0 {                             out <- i // Send'i' to 'out'.                    }          } } // Theprime sieve: Daisy-chain Filter processes. funcmain() {          ch := make(chan int) // Create a newchannel.          go Generate(ch)      // Launch Generate goroutine.          for i := 0; i < 10; i++ {                    prime := <-ch                    print(prime, "n")                    ch1 := make(chan int)                    go Filter(ch, ch1, prime)                    ch = ch1          } }

      上面的程序創(chuàng)建了10個(gè)Filter,每個(gè)分別過(guò)濾一個(gè)素?cái)?shù),所以可以輸出前10個(gè)素?cái)?shù)。

      Chain-Filter通過(guò)簡(jiǎn)單的代碼創(chuàng)建并發(fā)的過(guò)濾器鏈。這種辦法還有一個(gè)好處,就是每個(gè)通道只有兩個(gè)協(xié)程會(huì)訪問(wèn),就不會(huì)有激烈的競(jìng)爭(zhēng),性能會(huì)比較好

      6、共享變量

      協(xié)程之間的通信只能夠通過(guò)通道。但是我們習(xí)慣于共享變量,而且很多時(shí)候使用共享變量能讓代碼更簡(jiǎn)潔。比如一個(gè)Server有兩個(gè)狀態(tài)開(kāi)和關(guān)。其他僅僅希望獲取或改變其狀態(tài),那又該如何做呢??梢詫⑦@個(gè)變量至于0通道中,并使用一個(gè)協(xié)程來(lái)維護(hù)。

      go語(yǔ)言中并發(fā)圖文教程

      下面的例子描述如何用這個(gè)方式,實(shí)現(xiàn)一個(gè)共享變量。

      //共享變量有一個(gè)讀通道和一個(gè)寫(xiě)通道組成 typesharded_var struct {          reader chan int          writer chan int } //共享變量維護(hù)協(xié)程 funcsharded_var_whachdog(v sharded_var) {          go func() {                    //初始值                    var value int = 0                    for {                             //監(jiān)聽(tīng)讀寫(xiě)通道,完成服務(wù)                             select {                             case value =<-v.writer:                             case v.reader <-value:                             }                    }          }() } funcmain() {          //初始化,并開(kāi)始維護(hù)協(xié)程          v := sharded_var{make(chan int),make(chan int)}          sharded_var_whachdog(v)          //讀取初始值          fmt.Println(<-v.reader)          //寫(xiě)入一個(gè)值          v.writer <- 1          //讀取新寫(xiě)入的值          fmt.Println(<-v.reader) }

      這樣,就可以在協(xié)程和通道的基礎(chǔ)上實(shí)現(xiàn)一個(gè)協(xié)程安全的共享變量了。定義一個(gè)寫(xiě)通道,需要更新變量的時(shí)候,往里寫(xiě)新的值。再定義一個(gè)讀通道,需要讀的時(shí)候,從里面讀。通過(guò)一個(gè)單獨(dú)的協(xié)程來(lái)維護(hù)這兩個(gè)通道。保證數(shù)據(jù)的一致性。

      一般來(lái)說(shuō),協(xié)程之間不推薦使用共享變量來(lái)交互,但是按照這個(gè)辦法,在一些場(chǎng)合,使用共享變量也是可取的。很多平臺(tái)上有較為原生的共享變量支持,到底用那種 實(shí)現(xiàn)比較好,就見(jiàn)仁見(jiàn)智了。另外利用協(xié)程和通道,可以還實(shí)現(xiàn)各種常見(jiàn)的并發(fā)數(shù)據(jù)結(jié)構(gòu),如鎖等等,就不一一贅述。

      7、協(xié)程泄漏

      協(xié)程和內(nèi)存一樣,是系統(tǒng)的資源。對(duì)于內(nèi)存,有自動(dòng)垃圾回收。但是對(duì)于協(xié)程,沒(méi)有相應(yīng)的回收機(jī)制。會(huì)不會(huì)若干年后,協(xié)程普及了,協(xié)程泄漏和內(nèi)存泄漏一樣成為 程序員永遠(yuǎn)的痛呢?

      一般而言,協(xié)程執(zhí)行結(jié)束后就會(huì)銷(xiāo)毀。協(xié)程也會(huì)占用內(nèi)存,如果發(fā)生協(xié)程泄漏,影響和內(nèi)存泄漏一樣嚴(yán)重。輕則拖慢程序,重則壓垮機(jī)器。

      C和C++都是沒(méi)有自動(dòng)內(nèi)存回收的程序設(shè)計(jì)語(yǔ)言,但只要有良好的編程習(xí)慣,就能解決規(guī)避問(wèn)題。對(duì)于協(xié)程是一樣的,只要有好習(xí)慣就可以了。

      只有兩種情況會(huì)導(dǎo)致協(xié)程無(wú)法結(jié)束。一種情況是協(xié)程想從一個(gè)通道讀數(shù)據(jù),但無(wú)人往這個(gè)通道寫(xiě)入數(shù)據(jù),或許這個(gè)通道已經(jīng)被遺忘了。還有一種情況是程想往一個(gè)通道寫(xiě)數(shù)據(jù),可是由于無(wú)人監(jiān)聽(tīng)這個(gè)通道,該協(xié)程將永遠(yuǎn)無(wú)法向下執(zhí)行。下面分別討論如何避免這兩種情況。

      對(duì)于協(xié)程想從一個(gè)通道讀數(shù)據(jù),但無(wú)人往這個(gè)通道寫(xiě)入數(shù)據(jù)這種情況。解決的辦法很簡(jiǎn)單,加入超時(shí)機(jī)制。對(duì)于有不確定會(huì)不會(huì)返回的情況,必須加入超時(shí),避免出 現(xiàn)永久等待。

      另外不一定要使用定時(shí)器才能終止協(xié)程。也可以對(duì)外暴露一個(gè)退出提醒通道。任何其他協(xié)程都可以通過(guò)該通道來(lái)提醒這個(gè)協(xié)程終止。

      go語(yǔ)言中并發(fā)圖文教程

      對(duì)于協(xié)程想往一個(gè)通道寫(xiě)數(shù)據(jù),但通道阻塞無(wú)法寫(xiě)入這種情況。解決的辦法也很簡(jiǎn)單,就是給通道加緩沖。但前提是這個(gè)通道只會(huì)接收到固定數(shù)目的寫(xiě)入。

      比方說(shuō), 已知一個(gè)通道最多只會(huì)接收N次數(shù)據(jù),那么就將這個(gè)通道的緩沖設(shè)置為N。那么該通道將永遠(yuǎn)不會(huì)堵塞,協(xié)程自然也不會(huì)泄漏。也可以將其緩沖設(shè)置為無(wú)限,不過(guò)這 樣就要承擔(dān)內(nèi)存泄漏的風(fēng)險(xiǎn)了。等協(xié)程執(zhí)行完畢后,這部分通道內(nèi)存將會(huì)失去引用,會(huì)被自動(dòng)垃圾回收掉。

      funcnever_leak(ch chan int) {          //初始化timeout,緩沖為1          timeout := make(chan bool, 1)          //啟動(dòng)timeout協(xié)程,由于緩存為1,不可能泄露          go func() {                    time.Sleep(1 * time.Second)                    timeout <- true          }()          //監(jiān)聽(tīng)通道,由于設(shè)有超時(shí),不可能泄露          select {          case <-ch:                    // a read from ch hasoccurred          case <-timeout:                    // the read from ch has timedout          } }

      上面是個(gè)避免泄漏例子。使用超時(shí)避免讀堵塞,使用緩沖避免寫(xiě)堵塞。

      和內(nèi)存里面的對(duì)象一樣,對(duì)于長(zhǎng)期存在的協(xié)程,我們不用擔(dān)心泄漏問(wèn)題。一是長(zhǎng)期存在,二是數(shù)量較少。要警惕的只有那些被臨時(shí)創(chuàng)建的協(xié)程,這些協(xié)程數(shù)量大且生 命周期短,往往是在循環(huán)中創(chuàng)建的,要應(yīng)用前面提到的辦法,避免泄漏發(fā)生。協(xié)程也是把雙刃劍,如果出問(wèn)題,不但沒(méi)能提高程序性能,反而會(huì)讓程序崩潰。但就像 內(nèi)存一樣,同樣有泄漏的風(fēng)險(xiǎn),但越用越溜了。

      并發(fā)模式之實(shí)現(xiàn)

      在并發(fā)編程大行其道的今天,對(duì)協(xié)程和通道的支持成為各個(gè)平臺(tái)比不可少的一部分。雖然各家有各家的叫法,但都能滿(mǎn)足協(xié)程的基本要求—并發(fā)執(zhí)行和可大量創(chuàng)建。筆者對(duì)他們的實(shí)現(xiàn)方式總結(jié)了一下。

      下面列舉一些已經(jīng)支持協(xié)程的常見(jiàn)的語(yǔ)言和平臺(tái)。

      go語(yǔ)言中并發(fā)圖文教程

      GoLang 和Scala作為最新的語(yǔ)言,一出生就有完善的基于協(xié)程并發(fā)功能。Erlang最為老資格的并發(fā)編程語(yǔ)言,返老還童。其他二線語(yǔ)言則幾乎全部在新的版本中加入了協(xié)程。

      令人驚奇的是C/C++和Java這三個(gè)世界上最主流的平臺(tái)沒(méi)有在對(duì)協(xié)程提供語(yǔ)言級(jí)別的原生支持。他們都背負(fù)著厚重的歷史,無(wú)法改變,也無(wú)需改變。但他們還有其他的辦法使用協(xié)程。

      Java平臺(tái)有很多方法實(shí)現(xiàn)協(xié)程:

      · 修改虛擬機(jī):對(duì)JVM打補(bǔ)丁來(lái)實(shí)現(xiàn)協(xié)程,這樣的實(shí)現(xiàn)效果好,但是失去了跨平臺(tái)的好處

      · 修改字節(jié)碼:在編譯完成后增強(qiáng)字節(jié)碼,或者使用新的JVM語(yǔ)言。稍稍增加了編譯的難度。

      · 使用JNI:在Jar包中使用JNI,這樣易于使用,但是不能跨平臺(tái)。

      · 使用線程模擬協(xié)程:使協(xié)程重量級(jí),完全依賴(lài)JVM的線程實(shí)現(xiàn)。

      其中修改字節(jié)碼的方式比較常見(jiàn)。因?yàn)檫@樣的實(shí)現(xiàn)辦法,可以平衡性能和移植性。最具代表性的JVM語(yǔ)言Scale就能很好的支持協(xié)程并發(fā)。流行的Java Actor模型類(lèi)庫(kù)akka也是用修改字節(jié)碼的方式實(shí)現(xiàn)的協(xié)程。

      對(duì)于C語(yǔ)言,協(xié)程和線程一樣??梢允褂酶鞣N各樣的系統(tǒng)調(diào)用來(lái)實(shí)現(xiàn)。協(xié)程作為一個(gè)比較高級(jí)的概念,實(shí)現(xiàn)方式實(shí)在太多,就不討論了。比較主流的實(shí)現(xiàn)有l(wèi)ibpcl, coro,lthread等等。

      對(duì)于C++,有Boost實(shí)現(xiàn),還有一些其他開(kāi)源庫(kù)。還有一門(mén)名為μC++語(yǔ)言,在C++基礎(chǔ)上提供了并發(fā)擴(kuò)展。

      可見(jiàn)這種編程模型在眾多的語(yǔ)言平臺(tái)中已經(jīng)得到了廣泛的支持,不再小眾。如果想使用的話,隨時(shí)可以加到自己的工具箱中。

      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)