golang并發(fā)----基礎(chǔ)

Channels

創(chuàng)建channel

使用內(nèi)置的make函數(shù),我們可以創(chuàng)建一個(gè)channel

// ch has type 'chan int'
ch := make(chan int) //  unbuffered channel
ch = make(chan int, 0) // unbuffered channel
ch = make(chan int, 3) // buffered channel with capacity 3

引用類型&零值&比較

  • 和map類似,channel也對(duì)應(yīng)一個(gè)make創(chuàng)建的底層數(shù)據(jù)結(jié)構(gòu)的引用.當(dāng)我們復(fù)制一個(gè)channel或用于函數(shù)參數(shù)傳遞時(shí),我們只是拷貝了一個(gè)channel引用,因此調(diào)用者和被調(diào)用者將引用同一個(gè)channel對(duì)象.
  • 和其它的引用類型一樣,channel的零值也是nil.
  • 兩個(gè)相同類型的channel可以使用==運(yùn)算符比較

發(fā)送&接收

一個(gè)發(fā)送語(yǔ)句將一個(gè)值從一個(gè)goroutine通過(guò)channel發(fā)送到另一個(gè)執(zhí)行接收操作的goroutine

ch <- x  // a send statement
x = <-ch // a receive expression in an assignment statement
<-ch     // a receive statement; result is discarded

關(guān)閉channel

只有發(fā)送者需要關(guān)閉通道,接收者永遠(yuǎn)不會(huì)需要關(guān)閉通道

  • 如果channel關(guān)閉,隨后對(duì)基于該channel的任何發(fā)送操作都將導(dǎo)致panic異常
  • 對(duì)一個(gè)已經(jīng)被close過(guò)的channel進(jìn)行接收操作依然可以接受到之前已經(jīng)成功發(fā)送的數(shù)據(jù)
  • 如果channel中已經(jīng)沒有數(shù)據(jù)的話將產(chǎn)生一個(gè)零值的數(shù)據(jù)
  • 使用內(nèi)置的close函數(shù)就可以關(guān)閉一個(gè)channel:close(ch),通常是配合defer使用

其實(shí)你并不需要關(guān)閉每一個(gè)channel.
只有當(dāng)需要告訴接收者goroutine,所有的數(shù)據(jù)已經(jīng)全部發(fā)送時(shí)才需要關(guān)閉channel.
不管一個(gè)channel是否被關(guān)閉,當(dāng)它沒有被引用時(shí)將會(huì)被Go語(yǔ)言的垃圾自動(dòng)回收器回收.

關(guān)閉一個(gè)channels還會(huì)觸發(fā)一個(gè)廣播機(jī)制
所有channel接收者都會(huì)在channel關(guān)閉時(shí) 立刻從阻塞等待中返回 ok值為false 這個(gè)廣播機(jī)制經(jīng)常被利用進(jìn)行向多個(gè)訂閱者同時(shí)發(fā)送信號(hào) 例如退出信號(hào)

不帶緩存的Channels(同步channel)

基于無(wú)緩存Channels的發(fā)送和接收操作將導(dǎo)致兩個(gè)goroutine做一次同步操作
一個(gè)基于無(wú)緩存Channels的發(fā)送操作將導(dǎo)致發(fā)送者goroutine阻塞,直到另一個(gè)goroutine在相同的Channels上執(zhí)行接收操作.
當(dāng)發(fā)送的值通過(guò)Channels成功傳輸之后,兩個(gè)goroutine可以繼續(xù)執(zhí)行后面的語(yǔ)句.
如果接收操作先發(fā)生,那么接收者goroutine也將阻塞,直到有另一個(gè)goroutine在相同的Channels上執(zhí)行發(fā)送操作.

關(guān)于同步&并發(fā)
  • 同步
    當(dāng)我們說(shuō)x事件在y事件之前發(fā)生(happens before),我們并不是說(shuō)x事件在時(shí)間上比y時(shí)間更早,我們要表達(dá)的意思是要保證在此之前的事件都已經(jīng)完成了.
    例如在此之前的更新某些變量的操作已經(jīng)完成,你可以放心依賴這些已完成的事件了
  • 并發(fā)
    當(dāng)我們說(shuō)x事件既不是在y事件之前發(fā)生也不是在y事件之后發(fā)生,我們就說(shuō)x事件和y事件是并發(fā)的疗绣。這并不是意味著x事件和y事件就一定是同時(shí)發(fā)生的,我們只是不能確定這兩個(gè)事件發(fā)生的先后順序.
func main() {
    out := make(chan int)
    // 這里向out發(fā)送數(shù)據(jù),但是并沒有另外一個(gè)goroutine來(lái)接收out的值
    out <- 2
    go func(in chan int) {
        fmt.Println(<-in)
    }(out)
    // fatal error: all goroutines are asleep - deadlock!
}
消息事件

基于channels發(fā)送消息有兩個(gè)重要方面:

  • 每個(gè)消息都有一個(gè)有意義的值,channel單純用來(lái)傳輸數(shù)據(jù)
  • 有時(shí)候希望強(qiáng)調(diào)通訊發(fā)生的時(shí)刻時(shí),我們將它稱為消息事件.這些消息事件并不攜帶額外的信息,它僅僅是用作兩個(gè)goroutine之間的同步.這時(shí)候可以傳struct{}/bool/1這種值.
func main() {
    conn, err := net.Dial("tcp", "localhost:8000")
    if err != nil {
        log.Fatal(err)
    }
    done := make(chan struct{})
    go func() {
        io.Copy(os.Stdout, conn) // NOTE: ignoring errors
        log.Println("done")
        done <- struct{}{} // signal the main goroutine
    }()
    mustCopy(conn, os.Stdin)
    conn.Close()
    <-done // wait for background goroutine to finish
}

帶緩存的Channels

帶緩存的Channel內(nèi)部持有一個(gè)元素隊(duì)列,隊(duì)列的最大容量是在調(diào)用make函數(shù)創(chuàng)建channel時(shí)通過(guò)第二個(gè)參數(shù)指定的.
向緩存Channel的發(fā)送操作就是向內(nèi)部緩存隊(duì)列的尾部插入元素,接收操作則是從隊(duì)列的頭部刪除元素.
如果內(nèi)部緩存隊(duì)列是滿的,那么發(fā)送操作將阻塞直到因另一個(gè)goroutine執(zhí)行接收操作而釋放了新的隊(duì)列空間.
如果channel是空的,接收操作將阻塞直到有另一個(gè)goroutine執(zhí)行!!!

串聯(lián)的Channels(Pipeline)

串聯(lián)Channels的管道可以用在需要長(zhǎng)時(shí)間運(yùn)行的服務(wù)中,每個(gè)長(zhǎng)時(shí)間運(yùn)行的goroutine可能會(huì)包含一個(gè)死循環(huán),在不同goroutine的死循環(huán)內(nèi)部使用串聯(lián)的Channels來(lái)通信.

檢測(cè)關(guān)閉的channel

如果發(fā)送者知道,沒有更多的值需要發(fā)送到channel的話,那么讓接收者也能及時(shí)知道沒有多余的值可接收將是有用的,因?yàn)榻邮照呖梢酝V共槐匾慕邮盏却?在發(fā)送方關(guān)閉channel即可.
但是在發(fā)送方關(guān)閉這個(gè)channel后,接收方依然會(huì)收到一個(gè)永無(wú)休止的零值序列.

  • if v,ok:=<-ch;!ok{break}
  • for v:=range ch{} // 當(dāng)channel被關(guān)閉并且沒有值可接收時(shí)跳出循環(huán)

goroutines泄漏,和垃圾變量不同,泄漏的goroutines并不會(huì)被自動(dòng)回收.因此確保每個(gè)不再需要的goroutine能正常退出是重要的!!!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末宅倒,一起剝皮案震驚了整個(gè)濱河市漩怎,隨后出現(xiàn)的幾起案子委刘,更是在濱河造成了極大的恐慌李茫,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,639評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件歧强,死亡現(xiàn)場(chǎng)離奇詭異哪廓,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)侣滩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門口注,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人君珠,你說(shuō)我怎么就攤上這事寝志。” “怎么了葛躏?”我有些...
    開封第一講書人閱讀 157,221評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵澈段,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我舰攒,道長(zhǎng)败富,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,474評(píng)論 1 283
  • 正文 為了忘掉前任摩窃,我火速辦了婚禮兽叮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘猾愿。我一直安慰自己鹦聪,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評(píng)論 6 386
  • 文/花漫 我一把揭開白布蒂秘。 她就那樣靜靜地躺著泽本,像睡著了一般。 火紅的嫁衣襯著肌膚如雪姻僧。 梳的紋絲不亂的頭發(fā)上规丽,一...
    開封第一講書人閱讀 49,816評(píng)論 1 290
  • 那天蒲牧,我揣著相機(jī)與錄音,去河邊找鬼赌莺。 笑死冰抢,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的艘狭。 我是一名探鬼主播挎扰,決...
    沈念sama閱讀 38,957評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼巢音!你這毒婦竟也來(lái)了遵倦?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,718評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤港谊,失蹤者是張志新(化名)和其女友劉穎骇吭,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體歧寺,經(jīng)...
    沈念sama閱讀 44,176評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡燥狰,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了斜筐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片龙致。...
    茶點(diǎn)故事閱讀 38,646評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖顷链,靈堂內(nèi)的尸體忽然破棺而出目代,到底是詐尸還是另有隱情,我是刑警寧澤嗤练,帶...
    沈念sama閱讀 34,322評(píng)論 4 330
  • 正文 年R本政府宣布榛了,位于F島的核電站,受9級(jí)特大地震影響煞抬,放射性物質(zhì)發(fā)生泄漏霜大。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評(píng)論 3 313
  • 文/蒙蒙 一革答、第九天 我趴在偏房一處隱蔽的房頂上張望战坤。 院中可真熱鬧,春花似錦残拐、人聲如沸途茫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)囊卜。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間栅组,已是汗流浹背袱衷。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留笑窜,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,358評(píng)論 2 360
  • 正文 我出身青樓登疗,卻偏偏與公主長(zhǎng)得像排截,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子辐益,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評(píng)論 2 348

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