Go語(yǔ)言基礎(chǔ)學(xué)習(xí) - 并發(fā)

      網(wǎng)友投稿 772 2022-05-30

      Go is an open source programming language? that makes it wasy to build simple, reliable, and efficient software.

      - golang.org

      跟隨golang官網(wǎng)教程,學(xué)習(xí)Go語(yǔ)言基礎(chǔ)知識(shí) - 并發(fā), 參考鏈接https://tour.go-zh.org/list。Let's go!

      并發(fā)

      goroutine

      Go 程(goroutine)是由 Go 運(yùn)行時(shí)管理的輕量級(jí)線程。

      go?f(x,?y,?z)

      會(huì)啟動(dòng)一個(gè)新的 Go 程并執(zhí)行

      f(x,?y,?z)

      f,?x,?y?和?z?的求值發(fā)生在當(dāng)前的 Go 程中,而?f?的執(zhí)行發(fā)生在新的 Go 程中。

      Go 程在相同的地址空間中運(yùn)行,因此在訪問(wèn)共享的內(nèi)存時(shí)必須進(jìn)行同步。sync?包提供了這種能力,不過(guò)在 Go 中并不經(jīng)常用到,因?yàn)檫€有其它的辦法(見(jiàn)下一頁(yè))。

      package?main import?( "fmt" "time" ) func?say(s?string)?{ for?i?:=?0;?i?

      信道

      信道是帶有類(lèi)型的管道,你可以通過(guò)它用信道操作符?<-?來(lái)發(fā)送或者接收值。先進(jìn)先出!

      ch?<-?v????//?將?v?發(fā)送至信道?ch。 v?:=?<-ch??//?從?ch?接收值并賦予?v。

      (“箭頭”就是數(shù)據(jù)流的方向。)

      和映射與切片一樣,信道在使用前必須創(chuàng)建:

      ch?:=?make(chan?int)

      默認(rèn)情況下,發(fā)送和接收操作在另一端準(zhǔn)備好之前都會(huì)阻塞。這使得 Go 程可以在沒(méi)有顯式的鎖或競(jìng)態(tài)變量的情況下進(jìn)行同步。

      以下示例對(duì)切片中的數(shù)進(jìn)行求和,將任務(wù)分配給兩個(gè) Go 程。一旦兩個(gè) Go 程完成了它們的計(jì)算,它就能算出最終的結(jié)果。

      package?main import?"fmt" func?sum(s?[]int,?c?chan?int)?{ sum?:=?0 for?_,?v?:=?range?s?{ sum?+=?v } c?<-?sum?//?將和送入?c } func?main()?{ s?:=?[]int{7,?2,?8,?-9,?4,?0} c?:=?make(chan?int) go?sum(s[:len(s)/2],?c) go?sum(s[len(s)/2:],?c) x,?y?:=?<-c,?<-c?//?從?c?中接收 fmt.Println(x,?y,?x+y) } //?output -5?17?12

      帶緩沖的信道

      信道可以是?帶緩沖的。將緩沖長(zhǎng)度作為第二個(gè)參數(shù)提供給?make?來(lái)初始化一個(gè)帶緩沖的信道:

      ch?:=?make(chan?int,?100)

      僅當(dāng)信道的緩沖區(qū)填滿后,向其發(fā)送數(shù)據(jù)時(shí)才會(huì)阻塞。當(dāng)緩沖區(qū)為空時(shí),接受方會(huì)阻塞。

      修改示例填滿緩沖區(qū),然后看看會(huì)發(fā)生什么。

      package?main import?"fmt" func?main()?{ ch?:=?make(chan?int,?2) ch?<-?1 ch?<-?2 ch?<-?3 fmt.Println(<-ch) fmt.Println(<-ch) } //?output fatal?error:?all?goroutines?are?asleep?-?deadlock! goroutine?1?[chan?send]: main.main() /tmp/sandbox029074443/prog.go:9?+0xa0

      range 和 close

      發(fā)送者可通過(guò)?close?關(guān)閉一個(gè)信道來(lái)表示沒(méi)有需要發(fā)送的值了。接收者可以通過(guò)為接收表達(dá)式分配第二個(gè)參數(shù)來(lái)測(cè)試信道是否被關(guān)閉:若沒(méi)有值可以接收且信道已被關(guān)閉,那么在執(zhí)行完

      v,?ok?:=?<-ch

      之后?ok?會(huì)被設(shè)置為?false。

      循環(huán)?for i := range c?會(huì)不斷從信道接收值,直到它被關(guān)閉。

      *注意:* 只有發(fā)送者才能關(guān)閉信道,而接收者不能。向一個(gè)已經(jīng)關(guān)閉的信道發(fā)送數(shù)據(jù)會(huì)引發(fā)程序恐慌(panic)。

      *還要注意:* 信道與文件不同,通常情況下無(wú)需關(guān)閉它們。只有在必須告訴接收者不再有需要發(fā)送的值時(shí)才有必要關(guān)閉,例如終止一個(gè)?range?循環(huán)。

      Go語(yǔ)言基礎(chǔ)學(xué)習(xí) - 并發(fā)

      package?main import?( "fmt" ) func?fibonacci(n?int,?c?chan?int)?{ x,?y?:=?0,?1 for?i?:=?0;?i?

      select 語(yǔ)句

      select?語(yǔ)句使一個(gè) Go 程可以等待多個(gè)通信操作。

      select?會(huì)阻塞到某個(gè)分支可以繼續(xù)執(zhí)行為止,這時(shí)就會(huì)執(zhí)行該分支。當(dāng)多個(gè)分支都準(zhǔn)備好時(shí)會(huì)隨機(jī)選擇一個(gè)執(zhí)行。

      package?main import?"fmt" func?fibonacci(c,?quit?chan?int)?{ x,?y?:=?0,?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?

      默認(rèn)選擇

      當(dāng)?select?中的其它分支都沒(méi)有準(zhǔn)備好時(shí),default?分支就會(huì)執(zhí)行。

      為了在嘗試發(fā)送或者接收時(shí)不發(fā)生阻塞,可使用?default?分支:

      select?{ case?i?:=?<-c: ????//?使用?i default: ????//?從?c?中接收會(huì)阻塞時(shí)執(zhí)行 }

      package?main import?( "fmt" "time" ) func?main()?{ tick?:=?time.Tick(100?*?time.Millisecond) boom?:=?time.After(500?*?time.Millisecond) for?{ select?{ case?<-tick: fmt.Println("tick.") case?<-boom: fmt.Println("BOOM!") return default: fmt.Println("????.") time.Sleep(50?*?time.Millisecond) } } } //?output ????. ????. tick. ????.? ????. tick. ????.? ????. tick. ????. ????. tick. ????. ????. BOOM!

      sync.Mutex

      我們已經(jīng)看到信道非常適合在各個(gè) Go 程間進(jìn)行通信。

      但是如果我們并不需要通信呢?比如說(shuō),若我們只是想保證每次只有一個(gè) Go 程能夠訪問(wèn)一個(gè)共享的變量,從而避免沖突?

      這里涉及的概念叫做 *互斥(mutual*exclusion)* ,我們通常使用 *互斥鎖(Mutex)* 這一數(shù)據(jù)結(jié)構(gòu)來(lái)提供這種機(jī)制。

      Go 標(biāo)準(zhǔn)庫(kù)中提供了?sync.Mutex?互斥鎖類(lèi)型及其兩個(gè)方法:

      Lock

      Unlock

      我們可以通過(guò)在代碼前調(diào)用?Lock?方法,在代碼后調(diào)用?Unlock?方法來(lái)保證一段代碼的互斥執(zhí)行。參見(jiàn)?Inc?方法。

      我們也可以用?defer?語(yǔ)句來(lái)保證互斥鎖一定會(huì)被解鎖。參見(jiàn)?Value?方法。

      package?main import?( "fmt" "sync" "time" ) //?SafeCounter?的并發(fā)使用是安全的。 type?SafeCounter?struct?{ v???map[string]int mux?sync.Mutex } //?Inc?增加給定?key?的計(jì)數(shù)器的值。 func?(c?*SafeCounter)?Inc(key?string)?{ c.mux.Lock() //?Lock?之后同一時(shí)刻只有一個(gè)?goroutine?能訪問(wèn)?c.v c.v[key]++ c.mux.Unlock() } //?Value?返回給定?key?的計(jì)數(shù)器的當(dāng)前值。 func?(c?*SafeCounter)?Value(key?string)?int?{ c.mux.Lock() //?Lock?之后同一時(shí)刻只有一個(gè)?goroutine?能訪問(wèn)?c.v defer?c.mux.Unlock() return?c.v[key] } func?main()?{ c?:=?SafeCounter{v:?make(map[string]int)} for?i?:=?0;?i?

      Go語(yǔ)言

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:技術(shù)干貨 | 模型優(yōu)化精度、速度我全都要!MindSpore模型精度調(diào)優(yōu)實(shí)戰(zhàn)(二)
      下一篇:移動(dòng)通信小知識(shí)學(xué)習(xí)筆記
      相關(guān)文章
      亚洲中文字幕久久无码| 亚洲avav天堂av在线网爱情| 亚洲永久网址在线观看| 亚洲综合一区二区| 色噜噜综合亚洲av中文无码| 亚洲电影中文字幕| 久久综合图区亚洲综合图区| 久久久久久a亚洲欧洲aⅴ| 中文字幕专区在线亚洲| jlzzjlzz亚洲乱熟在线播放| 亚洲精品无码99在线观看 | 亚洲精品成人片在线观看精品字幕| 亚洲福利在线播放| 一区二区三区亚洲视频| 亚洲av午夜精品一区二区三区 | 亚洲91av视频| 亚洲第一中文字幕| 亚洲国产综合精品中文第一区| 亚洲AV无码成人网站久久精品大 | 亚洲成Av人片乱码色午夜| 亚洲国产成人AV在线播放| 亚洲一区在线视频| 久久久久精品国产亚洲AV无码| 亚洲一区二区三区免费视频| 亚洲AV无码国产精品色| 亚洲首页国产精品丝袜| 亚洲国产精品无码久久九九大片| 亚洲第一综合天堂另类专| 国产精品亚洲а∨无码播放麻豆| 婷婷亚洲天堂影院| 亚洲黄黄黄网站在线观看| 亚洲综合无码AV一区二区 | 国产精品亚洲аv无码播放| 亚洲αv久久久噜噜噜噜噜| 亚洲狠狠综合久久| 亚洲国产精品专区| 亚洲AV成人影视在线观看| 人人狠狠综合久久亚洲| 亚洲成人国产精品| 亚洲开心婷婷中文字幕| 久久久久亚洲AV无码永不|