go并發(fā)(一)

前幾天被小伙伴發(fā)現(xiàn)半年前寫(xiě)的代碼里面有一個(gè)并發(fā)的bug『菰梗回想一下,golang并發(fā)這邊的知識(shí)確實(shí)忘得差不多了邑遏,打算寫(xiě)兩篇筆記記錄一下佣赖。golang里的并發(fā)主要有兩種,一種是使用goroutine(類似于線程)并通過(guò)channel實(shí)現(xiàn)線程間通信记盒;另一種是通過(guò)shared variables來(lái)實(shí)現(xiàn)憎蛤。我們先來(lái)看看第一種

goroutine

首先我們來(lái)看一個(gè)goroutine的例子

func main (){
  go func() {
    for i := 0; i < 10; i++ {
      fmt.Println("foo", i)
    }
  }()
  fmt.Println("bar")
}

上面的go foo()開(kāi)了一個(gè)新的goroutine,但是它并不會(huì)跑完(可能能跑一兩個(gè)循環(huán)),因?yàn)閙ain先退出了纪吮,整個(gè)程序也就結(jié)束了俩檬。為了讓它能夠跑完栏豺,我們可以讓main等一等它。

var wg sync.WaitGroup

func main (){
  wg.Add(1)
  go func() {
    defer wg.Done()
    for i := 0; i < 10; i++ {
      fmt.Println("foo", i)
    }
  }()
  fmt.Println("bar")
  wg.Wait()
}

為了顯示他們是并發(fā)的豆胸,我們多開(kāi)幾個(gè)goroutine,看他們的輸出是否是亂序的奥洼。

var wg sync.WaitGroup

func foo(s string){
  defer wg.Done()
  for i := 0; i < 10; i++ {
    fmt.Println(s, i)
  }
}

func main (){
  wg.Add(3)
  go foo("foo")
  go foo("oof")
  go foo("bar")
  wg.Wait()
}

有興趣的同學(xué)可以看看net/http是如何使用goroutine的

Channels

"If goroutines are the activities of a concurrent go program, channels are the connections between them"
這句話是對(duì)channel最好的解釋了。channel用于在goroutine之間傳遞值晚胡,是一種"線程"間通信方式灵奖。

ch := make(chan int)   //創(chuàng)建一個(gè)unbuffered channel
ch := make(chan int, 3) //創(chuàng)建一個(gè)buffered channel,容量為3
ch <- x  //發(fā)送值到channel
x = <- ch //從channel中取出值
<- ch //取值并丟棄
close(ch) //關(guān)閉channel

語(yǔ)法太簡(jiǎn)單了!這年頭連編程語(yǔ)言都要擬物化了估盘!

unbuffered channel

發(fā)送數(shù)據(jù)到unbuffered channel的操作會(huì)阻塞發(fā)送的goroutine,直到有某個(gè)線程接收了這個(gè)channel的值瓷患。而如果一個(gè)goroutine試圖去一個(gè)沒(méi)有值的channel上取值,它也會(huì)被阻塞遣妥,直到這個(gè)channel上被發(fā)送了值擅编。

func main() {
  c := make(chan int)
  go func(c chan int) {
    time.Sleep(3 * time.Second)
    fmt.Println("before received")
    fmt.Println(<- c)
  }(c)
  c <- 1
  fmt.Println("after received")
}

運(yùn)行上面代碼我們明顯看到,在channel中的值被讀取之前箫踩,main被阻塞了爱态,直到channel被讀取,main才繼續(xù)運(yùn)行境钟。

func main() {
  c := make(chan int)
  go func(c chan int) {
    fmt.Println(<- c)
    fmt.Println("after received")
  }(c)
  time.Sleep(3 * time.Second)
  fmt.Println("before sending")
  c <- 1
  time.Sleep(1 * time.Second)
}

上面的代碼中锦担,新開(kāi)的goroutine首先去讀channel,可是由于channel中沒(méi)有值,所以它被阻塞了慨削,直到main中向channel發(fā)送值洞渔,goroutine才拿到它想要的值并繼續(xù)運(yùn)行。

close channel

發(fā)送完成后缚态,可以關(guān)閉channel磁椒,關(guān)閉后所有對(duì)這個(gè)channel的寫(xiě)操作都會(huì)panic,而讀操作依舊可以進(jìn)行,當(dāng)所有值都讀完后玫芦,繼續(xù)讀該channel會(huì)得到zero value

func main() {
  naturals := make(chan int)
  squares := make(chan int)

  go func() {
    for x := 0; x < 100 ;x++ {
      naturals <- x
    }
    close(naturals)
  }()

  go func() {
    for x := range naturals{
      squares <- x * x
    }
    close(squares)
  }()

  for x := range squares{
    fmt.Println(x)
  }
}

buffered channels

buffered channels是一個(gè)有限長(zhǎng)隊(duì)列浆熔,下面我們來(lái)創(chuàng)建一個(gè)容量為3的buffered channels

bc := make(chan int, 3)

如果bc里面已經(jīng)有了三個(gè)沒(méi)有被讀取的值,繼續(xù)往里面發(fā)送的話程序就會(huì)出錯(cuò)姨俩。我們可以用cap函數(shù)和len函數(shù)來(lái)檢查bc的容量以及里面現(xiàn)在有幾個(gè)值蘸拔。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末师郑,一起剝皮案震驚了整個(gè)濱河市环葵,隨后出現(xiàn)的幾起案子熄驼,更是在濱河造成了極大的恐慌旅掂,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,183評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蠕嫁,死亡現(xiàn)場(chǎng)離奇詭異地梨,居然都是意外死亡菊卷,警方通過(guò)查閱死者的電腦和手機(jī)缔恳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)洁闰,“玉大人歉甚,你說(shuō)我怎么就攤上這事∑嗣迹” “怎么了纸泄?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,766評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)腰素。 經(jīng)常有香客問(wèn)我聘裁,道長(zhǎng),這世上最難降的妖魔是什么弓千? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,854評(píng)論 1 299
  • 正文 為了忘掉前任衡便,我火速辦了婚禮,結(jié)果婚禮上洋访,老公的妹妹穿的比我還像新娘镣陕。我一直安慰自己,他們只是感情好姻政,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布茁彭。 她就那樣靜靜地躺著,像睡著了一般扶歪。 火紅的嫁衣襯著肌膚如雪理肺。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,457評(píng)論 1 311
  • 那天善镰,我揣著相機(jī)與錄音妹萨,去河邊找鬼。 笑死炫欺,一個(gè)胖子當(dāng)著我的面吹牛乎完,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播品洛,決...
    沈念sama閱讀 40,999評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼树姨,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了桥状?” 一聲冷哼從身側(cè)響起帽揪,我...
    開(kāi)封第一講書(shū)人閱讀 39,914評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎辅斟,沒(méi)想到半個(gè)月后转晰,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,465評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評(píng)論 3 342
  • 正文 我和宋清朗相戀三年查邢,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蔗崎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,675評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡扰藕,死狀恐怖缓苛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情邓深,我是刑警寧澤他嫡,帶...
    沈念sama閱讀 36,354評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站庐完,受9級(jí)特大地震影響钢属,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜门躯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評(píng)論 3 335
  • 文/蒙蒙 一淆党、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧讶凉,春花似錦染乌、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,514評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至褐望,卻和暖如春勒庄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瘫里。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,616評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工实蔽, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人谨读。 一個(gè)月前我還...
    沈念sama閱讀 49,091評(píng)論 3 378
  • 正文 我出身青樓局装,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親劳殖。 傳聞我的和親對(duì)象是個(gè)殘疾皇子铐尚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評(píng)論 2 360

推薦閱讀更多精彩內(nèi)容