最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go語言并發(fā)技術(shù)詳解

 更新時(shí)間:2014年10月29日 09:57:10   投稿:junjie  
這篇文章主要介紹了Go語言并發(fā)技術(shù)詳解,本文講解了goroutine、channels、Buffered Channels、Range和Close等內(nèi)容,需要的朋友可以參考下

有人把Go比作21世紀(jì)的C語言,第一是因?yàn)镚o語言設(shè)計(jì)簡單,第二,21世紀(jì)最重要的就是并行程序設(shè)計(jì),而Go從語言層面就支持了并行。

goroutine

goroutine是Go并行設(shè)計(jì)的核心。goroutine說到底其實(shí)就是線程,但是它比線程更小,十幾個(gè)goroutine可能體現(xiàn)在底層就是五六個(gè)線程,Go語言內(nèi)部幫你實(shí)現(xiàn)了這些goroutine之間的內(nèi)存共享。執(zhí)行g(shù)oroutine只需極少的棧內(nèi)存(大概是4~5KB),當(dāng)然會(huì)根據(jù)相應(yīng)的數(shù)據(jù)伸縮。也正因?yàn)槿绱?,可同時(shí)運(yùn)行成千上萬個(gè)并發(fā)任務(wù)。goroutine比thread更易用、更高效、更輕便。

goroutine是通過Go的runtime管理的一個(gè)線程管理器。goroutine通過go關(guān)鍵字實(shí)現(xiàn)了,其實(shí)就是一個(gè)普通的函數(shù)。

復(fù)制代碼 代碼如下:

go hello(a, b, c)

通過關(guān)鍵字go就啟動(dòng)了一個(gè)goroutine。我們來看一個(gè)例子

復(fù)制代碼 代碼如下:

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") //開一個(gè)新的Goroutines執(zhí)行
    say("hello") //當(dāng)前Goroutines執(zhí)行
}

// 以上程序執(zhí)行后將輸出:
// hello
// world
// hello
// world
// hello
// world
// hello
// world
// hello

我們可以看到go關(guān)鍵字很方便的就實(shí)現(xiàn)了并發(fā)編程。 上面的多個(gè)goroutine運(yùn)行在同一個(gè)進(jìn)程里面,共享內(nèi)存數(shù)據(jù),不過設(shè)計(jì)上我們要遵循:不要通過共享來通信,而要通過通信來共享。

runtime.Gosched()表示讓CPU把時(shí)間片讓給別人,下次某個(gè)時(shí)候繼續(xù)恢復(fù)執(zhí)行該goroutine。

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

channels

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

復(fù)制代碼 代碼如下:

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

channel通過操作符<-來接收和發(fā)送數(shù)據(jù)

復(fù)制代碼 代碼如下:

ch <- v    // 發(fā)送v到channel ch.
v := <-ch  // 從ch中接收數(shù)據(jù),并賦值給v

我們把這些應(yīng)用到我們的例子中來:

復(fù)制代碼 代碼如下:

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)
}

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

Buffered Channels

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

復(fù)制代碼 代碼如下:

ch := make(chan type, value)

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

我們看一下下面這個(gè)例子,你可以在自己本機(jī)測試一下,修改相應(yīng)的value值

復(fù)制代碼 代碼如下:

package main

import "fmt"

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

Range和Close

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

復(fù)制代碼 代碼如下:

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里面的數(shù)據(jù),直到該channel被顯式的關(guān)閉。上面代碼我們看到可以顯式的關(guān)閉channel,生產(chǎn)者通過內(nèi)置函數(shù)close關(guān)閉channel。關(guān)閉channel之后就無法再發(fā)送任何數(shù)據(jù)了,在消費(fèi)方可以通過語法v, ok := <-ch測試channel是否被關(guān)閉。如果ok返回false,那么說明channel已經(jīng)沒有任何數(shù)據(jù)并且已經(jīng)被關(guān)閉。

記住應(yīng)該在生產(chǎn)者的地方關(guān)閉channel,而不是消費(fèi)的地方去關(guān)閉它,這樣容易引起panic

另外記住一點(diǎn)的就是channel不像文件之類的,不需要經(jīng)常去關(guān)閉,只有當(dāng)你確實(shí)沒有任何發(fā)送數(shù)據(jù)了,或者你想顯式的結(jié)束range循環(huán)之類的。

Select

我們上面介紹的都是只有一個(gè)channel的情況,那么如果存在多個(gè)channel的時(shí)候,我們?cè)撊绾尾僮髂兀珿o里面提供了一個(gè)關(guān)鍵字select,通過select可以監(jiān)聽channel上的數(shù)據(jù)流動(dòng)。

select默認(rèn)是阻塞的,只有當(dāng)監(jiān)聽的channel中有發(fā)送或接收可以進(jìn)行時(shí)才會(huì)運(yùn)行,當(dāng)多個(gè)channel都準(zhǔn)備好的時(shí)候,select是隨機(jī)的選擇一個(gè)執(zhí)行的。

復(fù)制代碼 代碼如下:

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其實(shí)就是類似switch的功能,default就是當(dāng)監(jiān)聽的channel都沒有準(zhǔn)備好的時(shí)候,默認(rèn)執(zhí)行的(select不再阻塞等待channel)。

復(fù)制代碼 代碼如下:

select {
case i := <-c:
    // use i
default:
    // 當(dāng)c阻塞的時(shí)候執(zhí)行這里
}

超時(shí)

有時(shí)候會(huì)出現(xiàn)goroutine阻塞的情況,那么我們?nèi)绾伪苊庹麄€(gè)程序進(jìn)入阻塞的情況呢?我們可以利用select來設(shè)置超時(shí),通過如下的方式實(shí)現(xiàn):

復(fù)制代碼 代碼如下:

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包中有幾個(gè)處理goroutine的函數(shù):

Goexit

退出當(dāng)前執(zhí)行的goroutine,但是defer函數(shù)還會(huì)繼續(xù)調(diào)用

Gosched

讓出當(dāng)前goroutine的執(zhí)行權(quán)限,調(diào)度器安排其他等待的任務(wù)運(yùn)行,并在下次某個(gè)時(shí)候從該位置恢復(fù)執(zhí)行。

NumCPU

返回 CPU 核數(shù)量

NumGoroutine

返回正在執(zhí)行和排隊(duì)的任務(wù)總數(shù)

GOMAXPROCS

用來設(shè)置可以并行計(jì)算的CPU核數(shù)的最大值,并返回之前的值。

相關(guān)文章

  • golang如何解決go get命令無響應(yīng)問題

    golang如何解決go get命令無響應(yīng)問題

    文章介紹了在Go語言中處理由于官方庫被封禁導(dǎo)致依賴下載失敗的方法,包括設(shè)置代理和直接克隆依賴包到GOPATH/src下
    2024-12-12
  • 詳解Go語言如何熱重載和優(yōu)雅地關(guān)閉程序

    詳解Go語言如何熱重載和優(yōu)雅地關(guān)閉程序

    我們有時(shí)會(huì)因不同的目的去關(guān)閉服務(wù),一種關(guān)閉服務(wù)是終止操作系統(tǒng),一種關(guān)閉服務(wù)是用來更新配置,本文就來和大家簡單講講這兩種方法的實(shí)現(xiàn)吧
    2023-07-07
  • Go語言如何并發(fā)超時(shí)處理詳解

    Go語言如何并發(fā)超時(shí)處理詳解

    大家都知道golang并沒有在語言層次上提供超時(shí)操作,但可以通過一些小技巧實(shí)現(xiàn)超時(shí)。下面來一起看看吧,有需要的朋友們可以參考借鑒。
    2016-09-09
  • Go語言用map實(shí)現(xiàn)堆棧功能的方法

    Go語言用map實(shí)現(xiàn)堆棧功能的方法

    這篇文章主要介紹了Go語言用map實(shí)現(xiàn)堆棧功能的方法,實(shí)例分析了Go語言使用map操作堆棧的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-02-02
  • Go gRPC超時(shí)控制Deadlines用法詳解

    Go gRPC超時(shí)控制Deadlines用法詳解

    這篇文章主要為大家介紹了Go gRPC超時(shí)控制Deadlines用法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • Golang內(nèi)存管理之垃圾收集器詳解

    Golang內(nèi)存管理之垃圾收集器詳解

    這篇文章我們主要介紹垃圾收集器的設(shè)計(jì)原理以及Golang垃圾收集器的實(shí)現(xiàn)原理,文中有詳細(xì)的代碼示例及圖文介紹,感興趣的小伙伴跟著小編一起來學(xué)習(xí)吧
    2023-06-06
  • Golang 使用Map實(shí)現(xiàn)去重與set的功能操作

    Golang 使用Map實(shí)現(xiàn)去重與set的功能操作

    這篇文章主要介紹了Golang 使用 Map 實(shí)現(xiàn)去重與 set 的功能操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • GoZero中make后返回?cái)?shù)據(jù)與原數(shù)據(jù)不對(duì)齊的幾種解決方案

    GoZero中make后返回?cái)?shù)據(jù)與原數(shù)據(jù)不對(duì)齊的幾種解決方案

    在Go語言中,make是用來創(chuàng)建切片、映射(map)和通道(channel)的內(nèi)建函數(shù),但是,在使用 make 創(chuàng)建切片時(shí),若不理解如何正確使用其返回值,可能會(huì)遇到數(shù)據(jù)對(duì)不上或結(jié)果不符合預(yù)期的情況,本文將分析在GoZero或其他基于Go的應(yīng)用中,使用make時(shí)可能導(dǎo)致的問題及解決方案
    2025-01-01
  • golang實(shí)現(xiàn)webgis后端開發(fā)的步驟詳解

    golang實(shí)現(xiàn)webgis后端開發(fā)的步驟詳解

    這篇文章主要介紹如何用golang結(jié)合postgis數(shù)據(jù)庫,使用gin、grom框架實(shí)現(xiàn)后端的MVC的接口搭建,文中有詳細(xì)的流程步驟及代碼示例,需要的朋友可以參考下
    2023-06-06
  • goland 實(shí)現(xiàn)自動(dòng)格式化代碼

    goland 實(shí)現(xiàn)自動(dòng)格式化代碼

    這篇文章主要介紹了goland 實(shí)現(xiàn)自動(dòng)格式化代碼的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04

最新評(píng)論

苏尼特右旗| 连平县| 铁岭市| 大连市| 岳池县| 虎林市| 安仁县| 电白县| 易门县| 油尖旺区| 蓬莱市| 绥棱县| 静海县| 寿阳县| 汾阳市| 瑞安市| 高要市| 砀山县| 吉林省| 石林| 马公市| 曲松县| 松滋市| 宣恩县| 龙州县| 赞皇县| 舞阳县| 牙克石市| 渭源县| 旅游| 三明市| 德惠市| 砀山县| 浮梁县| 正宁县| 固安县| 翁牛特旗| 西安市| 东港市| 元氏县| 吉木萨尔县|