亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Golang > 正文

Go語言并發技術詳解

2020-04-01 19:24:29
字體:
來源:轉載
供稿:網友
這篇文章主要介紹了Go語言并發技術詳解,本文講解了goroutine、channels、Buffered Channels、Range和Close等內容,需要的朋友可以參考下
 

有人把Go比作21世紀的C語言,第一是因為Go語言設計簡單,第二,21世紀最重要的就是并行程序設計,而Go從語言層面就支持了并行。

goroutine

goroutine是Go并行設計的核心。goroutine說到底其實就是線程,但是它比線程更小,十幾個goroutine可能體現在底層就是五六個線程,Go語言內部幫你實現了這些goroutine之間的內存共享。執行goroutine只需極少的棧內存(大概是4~5KB),當然會根據相應的數據伸縮。也正因為如此,可同時運行成千上萬個并發任務。goroutine比thread更易用、更高效、更輕便。

goroutine是通過Go的runtime管理的一個線程管理器。goroutine通過go關鍵字實現了,其實就是一個普通的函數。

復制代碼代碼如下:

go hello(a, b, c)

 

通過關鍵字go就啟動了一個goroutine。我們來看一個例子

復制代碼代碼如下:

package main

 

import (
    "fmt"
    "runtime"
)

func say(s string) {
    for i := 0; i < 5; i++ {
        runtime.Gosched()
        fmt.Println(s)
    }
}

func main() {
    go say("world") //開一個新的Goroutines執行
    say("hello") //當前Goroutines執行
}

// 以上程序執行后將輸出:
// hello
// world
// hello
// world
// hello
// world
// hello
// world
// hello

 

我們可以看到go關鍵字很方便的就實現了并發編程。 上面的多個goroutine運行在同一個進程里面,共享內存數據,不過設計上我們要遵循:不要通過共享來通信,而要通過通信來共享。

runtime.Gosched()表示讓CPU把時間片讓給別人,下次某個時候繼續恢復執行該goroutine。

默認情況下,調度器僅使用單線程,也就是說只實現了并發。想要發揮多核處理器的并行,需要在我們的程序中顯式調用 runtime.GOMAXPROCS(n) 告訴調度器同時使用多個線程。GOMAXPROCS 設置了同時運行邏輯代碼的系統線程的最大數量,并返回之前的設置。如果n < 1,不會改變當前設置。以后Go的新版本中調度得到改進后,這將被移除。這里有一篇Rob介紹的關于并發和并行的文章:http://concur.rspace.googlecode.com/hg/talk/concur.html#landing-slide

channels

goroutine運行在相同的地址空間,因此訪問共享內存必須做好同步。那么goroutine之間如何進行數據的通信呢,Go提供了一個很好的通信機制channel。channel可以與Unix shell 中的雙向管道做類比:可以通過它發送或者接收值。這些值只能是特定的類型:channel類型。定義一個channel時,也需要定義發送到channel的值的類型。注意,必須使用make 創建channel:

復制代碼代碼如下:

ci := make(chan int)
cs := make(chan string)
cf := make(chan interface{})

 

channel通過操作符<-來接收和發送數據

復制代碼代碼如下:

ch <- v    // 發送v到channel ch.
v := <-ch  // 從ch中接收數據,并賦值給v

 

我們把這些應用到我們的例子中來:

復制代碼代碼如下:

package main

 

import "fmt"

func sum(a []int, c chan int) {
    total := 0
    for _, v := range a {
        total += v
    }
    c <- total  // send total to c
}

func main() {
    a := []int{7, 2, 8, -9, 4, 0}

    c := make(chan int)
    go sum(a[:len(a)/2], c)
    go sum(a[len(a)/2:], c)
    x, y := <-c, <-c  // receive from c

    fmt.Println(x, y, x + y)
}

 

默認情況下,channel接收和發送數據都是阻塞的,除非另一端已經準備好,這樣就使得Goroutines同步變的更加的簡單,而不需要顯式的lock。所謂阻塞,也就是如果讀?。╲alue := <-ch)它將會被阻塞,直到有數據接收。其次,任何發送(ch<-5)將會被阻塞,直到數據被讀出。無緩沖channel是在多個goroutine之間同步很棒的工具。

Buffered Channels

上面我們介紹了默認的非緩存類型的channel,不過Go也允許指定channel的緩沖大小,很簡單,就是channel可以存儲多少元素。ch:= make(chan bool, 4),創建了可以存儲4個元素的bool 型channel。在這個channel 中,前4個元素可以無阻塞的寫入。當寫入第5個元素時,代碼將會阻塞,直到其他goroutine從channel 中讀取一些元素,騰出空間。

復制代碼代碼如下:

ch := make(chan type, value)

 

value == 0 ! 無緩沖(阻塞)
value > 0 ! 緩沖(非阻塞,直到value 個元素)

 

我們看一下下面這個例子,你可以在自己本機測試一下,修改相應的value值

復制代碼代碼如下:

package main

 

import "fmt"

func main() {
    c := make(chan int, 2)//修改2為1就報錯,修改2為3可以正常運行
    c <- 1
    c <- 2
    fmt.Println(<-c)
    fmt.Println(<-c)
}

 

Range和Close

上面這個例子中,我們需要讀取兩次c,這樣不是很方便,Go考慮到了這一點,所以也可以通過range,像操作slice或者map一樣操作緩存類型的channel,請看下面的例子

復制代碼代碼如下:

package main

 

import (
    "fmt"
)

func fibonacci(n int, c chan int) {
    x, y := 1, 1
    for i := 0; i < n; i++ {
        c <- x
        x, y = y, x + y
    }
    close(c)
}

func main() {
    c := make(chan int, 10)
    go fibonacci(cap(c), c)
    for i := range c {
        fmt.Println(i)
    }
}


for i := range c能夠不斷的讀取channel里面的數據,直到該channel被顯式的關閉。上面代碼我們看到可以顯式的關閉channel,生產者通過內置函數close關閉channel。關閉channel之后就無法再發送任何數據了,在消費方可以通過語法v, ok := <-ch測試channel是否被關閉。如果ok返回false,那么說明channel已經沒有任何數據并且已經被關閉。

 

記住應該在生產者的地方關閉channel,而不是消費的地方去關閉它,這樣容易引起panic

另外記住一點的就是channel不像文件之類的,不需要經常去關閉,只有當你確實沒有任何發送數據了,或者你想顯式的結束range循環之類的。

Select

我們上面介紹的都是只有一個channel的情況,那么如果存在多個channel的時候,我們該如何操作呢,Go里面提供了一個關鍵字select,通過select可以監聽channel上的數據流動。

select默認是阻塞的,只有當監聽的channel中有發送或接收可以進行時才會運行,當多個channel都準備好的時候,select是隨機的選擇一個執行的。

 

復制代碼代碼如下:

package main

 

import "fmt"

func fibonacci(c, quit chan int) {
    x, y := 1, 1
    for {
        select {
        case c <- x:
            x, y = y, x + y
        case <-quit:
            fmt.Println("quit")
            return
        }
    }
}

func main() {
    c := make(chan int)
    quit := make(chan int)
    go func() {
        for i := 0; i < 10; i++ {
            fmt.Println(<-c)
        }
        quit <- 0
    }()
    fibonacci(c, quit)
}

 

在select里面還有default語法,select其實就是類似switch的功能,default就是當監聽的channel都沒有準備好的時候,默認執行的(select不再阻塞等待channel)。

復制代碼代碼如下:

select {
case i := <-c:
    // use i
default:
    // 當c阻塞的時候執行這里
}

 

超時

有時候會出現goroutine阻塞的情況,那么我們如何避免整個程序進入阻塞的情況呢?我們可以利用select來設置超時,通過如下的方式實現:

復制代碼代碼如下:

func main() {
    c := make(chan int)
    o := make(chan bool)
    go func() {
        for {
            select {
                case v := <- c:
                    println(v)
                case <- time.After(5 * time.Second):
                    println("timeout")
                    o <- true
                    break
            }
        }
    }()
    <- o
}

 

runtime goroutine

runtime包中有幾個處理goroutine的函數:

Goexit

退出當前執行的goroutine,但是defer函數還會繼續調用

Gosched

讓出當前goroutine的執行權限,調度器安排其他等待的任務運行,并在下次某個時候從該位置恢復執行。

NumCPU

返回 CPU 核數量

NumGoroutine

返回正在執行和排隊的任務總數

GOMAXPROCS

用來設置可以并行計算的CPU核數的最大值,并返回之前的值。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亲子乱一区二区三区电影| 日韩亚洲综合在线| 亚洲系列中文字幕| 欧美成人性色生活仑片| 成人在线播放av| 青青青国产精品一区二区| 57pao成人永久免费视频| 精品国偷自产在线视频| 欧美精品www在线观看| 国产精品久久久久久久久免费看| 菠萝蜜影院一区二区免费| 欧美亚洲成人精品| 草民午夜欧美限制a级福利片| 97精品久久久中文字幕免费| 欧美黑人国产人伦爽爽爽| 亚洲japanese制服美女| 国内精品一区二区三区| 亚洲精品白浆高清久久久久久| 九九精品视频在线观看| 日韩一二三在线视频播| 欧美综合在线第二页| 亚洲成人网在线观看| 欧美最顶级丰满的aⅴ艳星| 亚洲片在线资源| 国产成人精品视频在线| 91精品国产九九九久久久亚洲| 国产成人精品综合| 国产精品第一区| 国产精自产拍久久久久久| 91精品国产777在线观看| 日韩精品免费在线| 在线观看亚洲区| 成人精品在线视频| 欧美日韩国产页| 久久久久中文字幕| 中文字幕在线观看日韩| 亚洲国产精品专区久久| 亚洲伦理中文字幕| 亚洲男人7777| 国产精品av网站| 欧美午夜精品久久久久久浪潮| 亚洲自拍欧美色图| 在线观看久久久久久| 亚洲国产天堂久久综合| 久久精品国产亚洲精品| 国产精品白丝jk喷水视频一区| 美乳少妇欧美精品| 久久久久久久久久久91| 国产一区私人高清影院| 日韩精品在线私人| 国产亚洲免费的视频看| 精品无人区乱码1区2区3区在线| 美女黄色丝袜一区| 亚洲国产欧美一区二区三区同亚洲| 欧美高清自拍一区| 2019中文字幕在线观看| 日韩高清欧美高清| 欧美精品18videosex性欧美| 精品久久久久久久久久久久久久| 欧美日韩在线看| 亚洲国产毛片完整版| 国产亚洲精品久久久| 欧美视频在线观看免费| 欧美国产日韩xxxxx| 久久中文字幕在线视频| 欧美极品少妇xxxxⅹ喷水| 亚洲欧洲黄色网| 欧美xxxx综合视频| 精品女同一区二区三区在线播放| 好吊成人免视频| 91伊人影院在线播放| 欧美激情在线一区| 日韩精品极品在线观看| 68精品久久久久久欧美| 中文字幕日本精品| 91精品国产亚洲| 中文字幕亚洲一区二区三区五十路| 日本最新高清不卡中文字幕| 欧美老女人性视频| 亚洲天堂免费视频| 久久久精品一区二区三区| 日韩在线观看免费| 日韩欧美在线中文字幕| 亚洲成**性毛茸茸| 亚洲影视九九影院在线观看| 国产欧美精品日韩| 日韩久久精品电影| 最近2019中文字幕在线高清| 欧美精品一本久久男人的天堂| 精品成人在线视频| 91久久精品日日躁夜夜躁国产| 久久免费福利视频| 亚洲aaaaaa| 国产日韩欧美中文在线播放| 精品福利一区二区| 久久久久久国产精品美女| 视频一区视频二区国产精品| 亚洲人线精品午夜| 国产日韩欧美91| 国产在线视频一区| 亚洲乱码一区av黑人高潮| 欧美美女操人视频| 日韩av免费在线| 狠狠色狠狠色综合日日五| 国产精品一区二区久久| 亚洲aⅴ日韩av电影在线观看| 国产美女直播视频一区| 亚洲自拍偷拍视频| 国产精品久久9| 亚洲成av人片在线观看香蕉| 奇门遁甲1982国语版免费观看高清| 欧美老少做受xxxx高潮| 久久久久久美女| 欧美日韩亚洲精品内裤| 欧美日韩亚洲一区二区三区| 欧美视频一区二区三区…| 亚洲国产精品免费| 国产精品ⅴa在线观看h| 97在线观看免费| 欧美日韩亚洲系列| 欧美午夜精品在线| 久久久精品2019中文字幕神马| 亚洲欧美日韩久久久久久| 久久夜色精品国产亚洲aⅴ| 91国内揄拍国内精品对白| 日韩电影在线观看永久视频免费网站| 精品久久久91| 亚洲午夜性刺激影院| 国产伦精品一区二区三区精品视频| 精品久久国产精品| 国产女精品视频网站免费| 在线不卡国产精品| 国产精品福利在线观看| 中文日韩在线观看| 高清在线视频日韩欧美| 中文字幕欧美亚洲| 在线视频欧美日韩精品| 韩国国内大量揄拍精品视频| 伊是香蕉大人久久| 欧美日韩成人精品| 国产一区二区三区在线播放免费观看| 亚洲老板91色精品久久| 欧美日韩精品在线播放| 中文字幕亚洲欧美日韩在线不卡| 亚洲欧美精品suv| 久久久亚洲国产| 精品网站999www| 亚洲国产又黄又爽女人高潮的| 91精品国产91久久久久久久久| 国产免费一区二区三区香蕉精| 日本精品视频在线播放| 欧美日韩精品中文字幕| 精品久久中文字幕久久av| 另类专区欧美制服同性| 欧美日韩国产中字| 亚洲福利视频专区| 久久夜精品va视频免费观看| 亚洲精品成人久久电影| 久久影视电视剧凤归四时歌| 另类图片亚洲另类| 欧美理论电影在线播放| 中文字幕av一区二区三区谷原希美| 亚洲激情在线观看视频免费| 欧美在线视频免费|