日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

go 并发编程

發(fā)布時(shí)間:2024/3/24 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 go 并发编程 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

并發(fā)編程就是可以讓你的程序不是順序執(zhí)行的,而是可以多個(gè)分支同時(shí)進(jìn)行,在go中,這個(gè)分支也被稱為協(xié)程goroutine(輕量級(jí)線程)。

Go語言中使用goroutine非常簡單,只需要在調(diào)用函數(shù)的時(shí)候在前面加上go關(guān)鍵字,就可以為一個(gè)函數(shù)創(chuàng)建一個(gè)goroutine。

一個(gè)goroutine必定對(duì)應(yīng)一個(gè)函數(shù),可以創(chuàng)建多個(gè)goroutine去執(zhí)行相同的函數(shù)。

在程序啟動(dòng)時(shí),Go程序就會(huì)為main()函數(shù)創(chuàng)建一個(gè)默認(rèn)的goroutine。main函數(shù)結(jié)束,所有的goroutine都會(huì)結(jié)束。

package mainimport ("fmt""sync" )var total struct{sync.Mutexvalue int }func worker(wg *sync.WaitGroup) {defer wg.Done() //計(jì)數(shù)器值減一for i := 0; i < 100; i++ {total.Lock() //加鎖,其他線程想加鎖會(huì)發(fā)生阻塞,保證加鎖范圍內(nèi)的語句同一時(shí)刻只會(huì)有一個(gè)線程訪問total.value += itotal.Unlock() //解鎖} }func main() {var wg sync.WaitGroup //計(jì)數(shù)器,初始值0wg.Add(2) //對(duì)計(jì)數(shù)器進(jìn)行加2wg.Add(1)go worker(&wg) //開啟go routinego worker(&wg) //計(jì)數(shù)器要傳引用go worker(&wg)wg.Wait() //阻塞,知道計(jì)數(shù)器值變?yōu)?fmt.Println(total.value) }

上例中可以看到有加鎖語句,對(duì)多線程模型的程序而言,原子性操作進(jìn)行加鎖和解鎖都是有必要的。所謂的原子性操作,就是并發(fā)編程中“最小的且不可并行化的”操作。假如上文中的total.value += i同時(shí)有兩個(gè)線程執(zhí)行這句,假如此時(shí)value=2,i都為5,則執(zhí)行這兩句后,得到的結(jié)果為7,而不是12,所以可能會(huì)導(dǎo)致結(jié)果不正確。上面的是加的是互斥鎖,go中還有讀寫鎖sync.RWMutex

我們也可用sync/atomic包來進(jìn)行原子性操作(推薦)

func worker(wg *sync.WaitGroup) {defer wg.Done() //計(jì)數(shù)器值減一for i := 0; i < 100; i++ {atomic.AddInt64(&total.value, int64(i))} }

順序一致性內(nèi)存模型

順序一致性內(nèi)存模型有兩大特性。

  • 一個(gè)線程中所有操作必須按照程序的順序來執(zhí)行。
  • (不管程序是否同步)所有線程都只能看到一個(gè)單一的操作執(zhí)行順序。在順序一致性內(nèi)存模型中,每個(gè)操作都必須原子執(zhí)行且立刻對(duì)所有線程可見。

在Go語言中,同一個(gè)Goroutine線程內(nèi)部,順序一致性的模型是得到保證的。但是不同的Goroutine之間,并不滿足順序一致性的內(nèi)存模型。需要通過明確定義的同步事件來作為同步的參考。

goroutine奉行通過通信來共享內(nèi)存,其中,通道是在goroutine之間進(jìn)行同步的主要方法。用法如下:

package mainimport "fmt"var chan1 = make(chan bool) //建立一個(gè)無緩存通道(通道的緩存大小是0) var chan2 = make(chan bool)func work(job string) {fmt.Println("I want to work: ", job)chan1 <- true // 無緩存通道的發(fā)送操作總在對(duì)應(yīng)的接收操作前發(fā)生 推薦的做法// 無緩存通道只在有人接收的時(shí)候才能發(fā)送值,否則就會(huì)一直在阻塞。 }func study(book string) {fmt.Println("I want to study: ", book)close(chan1) //關(guān)閉通道后,接收者可以從通道中接收到零值 }func play(game string) {fmt.Println("I want to play: ", game)<- chan2 // 無緩存通道的接收總在對(duì)應(yīng)該通道的發(fā)生完成前 }func main() {go work("程序員")go study("go語言")go play("王者榮耀")<- chan1<- chan1chan2 <- false }

對(duì)于帶緩存的通道,其中C是通道的緩存大小,則表示通道最多可儲(chǔ)存C個(gè)值,達(dá)到這個(gè)值還沒有被接收,則發(fā)送會(huì)被阻塞。我們可以通過控制通道的緩存大小來控制并發(fā)執(zhí)行的goroutine的最大數(shù)目。可以使用內(nèi)置的len函數(shù)獲取通道內(nèi)元素的數(shù)量,使用cap函數(shù)獲取通道的容量。

例如:(此處僅當(dāng)示例)

package mainimport "fmt"var chan1 = make(chan bool) //建立一個(gè)無緩存通道(通道的緩存大小是0) var chan2 = make(chan bool) var chan3 = make(chan bool, 3)func work(job string) {fmt.Println("I want to work: ", job)//chan1 <- true // 無緩存通道的發(fā)送操作總在對(duì)應(yīng)的接收操作前發(fā)生chan3 <- true }func study(book string) {fmt.Println("I want to study: ", book)//close(chan1) //關(guān)閉通道后,接收者可以從通道中接收到零值chan3 <- true }func play(game string) {fmt.Println("I want to play: ", game)//<- chan2 // 無緩存通道的接收總在對(duì)應(yīng)該通道的發(fā)生完成前chan3 <- true }func main() {go work("程序員")go study("go語言")go play("王者榮耀")<- chan3<- chan3<- chan3//<- chan1//chan2 <- false }

通過select和default分支可以很容易實(shí)現(xiàn)一個(gè)goroutine的退出控制:

package mainimport ("fmt""time" )func work2(channel chan bool, phone chan int) {for {time.Sleep(time.Second)select {default:fmt.Println("I am 工作")case <- channel:fmt.Println("I am 下班")phone <- 1}} }func main() {ch := make(chan bool)phone := make(chan int, 10)for i := 0; i < 10; i++ {go work2(ch, phone)}time.Sleep(time.Second * 3)close(ch)for i := 0; i < 10; i++ {<-phone} }

上例也可用sync.WaitGroup,結(jié)合defer來進(jìn)行改進(jìn)。

package mainimport ("fmt""sync""time" )func work2(channel chan bool, wg *sync.WaitGroup) {defer wg.Done()for {time.Sleep(time.Second)select {default:fmt.Println("I am 工作")case <- channel:fmt.Println("I am 下班")return}} }func main() {ch := make(chan bool)var wg sync.WaitGroupfor i := 0; i < 10; i++ {wg.Add(1)go work2(ch, &wg)}time.Sleep(time.Second * 3)close(ch)wg.Wait() }

?關(guān)閉通道close

關(guān)于關(guān)閉通道需要注意的事情是,只有在通知接收方goroutine所有的數(shù)據(jù)都發(fā)送完畢的時(shí)候才需要關(guān)閉通道。通道是可以被垃圾回收機(jī)制回收的,它和關(guān)閉文件是不一樣的,在結(jié)束操作之后關(guān)閉文件是必須要做的,但關(guān)閉通道不是必須的。

關(guān)閉后的通道有以下特點(diǎn):

1.對(duì)一個(gè)關(guān)閉的通道再發(fā)送值就會(huì)導(dǎo)致panic。2.對(duì)一個(gè)關(guān)閉的通道進(jìn)行接收會(huì)一直獲取值直到通道為空。3.對(duì)一個(gè)關(guān)閉的并且沒有值的通道執(zhí)行接收操作會(huì)得到對(duì)應(yīng)類型的零值。4.關(guān)閉一個(gè)已經(jīng)關(guān)閉的通道會(huì)導(dǎo)致panic。

如果你的通道不往里存值了記得關(guān)閉通道

func main() {c := make(chan int)go func() {for i := 0; i < 5; i++ {c <- ifmt.Println("協(xié)程", i)}close(c) //假如不關(guān)閉通道,下面的線程還是會(huì)認(rèn)為這個(gè)通道能夠取出值,會(huì)陷入deadlock}()for {if data, ok := <-c; ok { // 用ok判斷channel是否能取出值fmt.Println(data)} else {break}}fmt.Println("main結(jié)束") }

context包 上下文

使用例子:

//素?cái)?shù)篩,并用context包來避免后臺(tái)goroutine內(nèi)存泄漏 package mainimport ("context""fmt" )//生成自然數(shù)序列 func GeneralNatural(ctx context.Context) chan int {ch := make(chan int)go func() {for i := 2; ; i++ {select {case <-ctx.Done():returndefault:ch <- i}}}()return ch }//通道過濾器: 刪除能被素?cái)?shù)整除的數(shù) func PrimerFilter(ctx context.Context, in <- chan int, primer int) chan int{out := make(chan int)go func() {for {var i intif i = <-in; i % primer != 0 {select {case <-ctx.Done():returndefault:out <- i //新的序列,比原來少了能被primer整除的數(shù)}}}}()return out }func main() {// 通過Context控制后臺(tái)Goroutine狀態(tài)ctx, cancel := context.WithCancel(context.Background())//返回其子context和取消函數(shù)cancelch := GeneralNatural(ctx) // 生產(chǎn)自然數(shù)序列 2,3,4,5,.....for i := 0; i < 100; i++ {prime := <-ch //新出現(xiàn)的素?cái)?shù)fmt.Printf("%v: %v\n", i+1, prime)ch = PrimerFilter(ctx, ch, prime) //過濾掉能被新出現(xiàn)的素?cái)?shù)整除的數(shù)}cancel()// cancel調(diào)用,即會(huì)往子Context的Done通道發(fā)送消息 }

總結(jié)

以上是生活随笔為你收集整理的go 并发编程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产精品无圣光 | 亚洲免费网站在线观看 | 中文字av| 国产伦精品视频一区二区三区 | 黑人日批视频 | 久久精品视频网站 | 国产叼嘿视频 | av大片免费观看 | 伊人久久综合影院 | 大香伊人久久 | 久久免费看毛片 | 国产又粗又长又黄视频 | 国产成人精品久久二区二区91 | 国产成人精品免费视频 | 欧美午夜性生活 | 精品国产乱码久久久久久久 | 亚洲综合日韩精品欧美综合区 | aise爱色av| 国产性生活一级片 | 久久精品国产清自在天天线 | 国产精品人人人人 | 少妇一级淫片免费播放 | 五级 黄 色 片 | 72种无遮挡啪啪的姿势 | 亚洲色偷精品一区二区三区 | 在线观看成年人视频 | 久久a毛片| 亚洲精品国产精品乱码 | 69av视频 | 台湾佬久久 | 一级片一级 | 嫩草影院在线免费观看 | 爱情岛av永久入口 | 国产精品美女久久久久图片 | 天天干天天爱天天操 | 粉嫩小箩莉奶水四溅在线观看 | 中文在线观看av | 午夜影视剧场 | 1级性生活片 | 亚洲美女偷拍 | 综合久久影院 | 国产精品欧美综合 | 欧美精品久久久久久久免费 | 男欢女爱久石 | 日本黄色动态图 | 国产主播啪啪 | 成人在线午夜 | 青青草视频在线免费观看 | 青青青国内视频在线观看软件 | 奇米综合网 | 特级西西444www | 99热在线播放 | 久婷婷| 日韩精品久久久久久免费 | 亚洲最大黄色网址 | 36d大奶| 大乳女喂男人吃奶 | 亚洲男人天堂2022 | 久草福利资源 | www.日韩在线观看 | 久久成人在线视频 | 日日爽日日操 | 日剧再来一次第十集 | 国产精品午夜未成人免费观看 | 免费av导航| 日韩成人精品 | 无限资源日本好片 | a天堂在线观看视频 | 五月激情婷婷网 | 日本大尺度吃奶做爰视频 | 鸥美毛片 | 精品国产av色一区二区深夜久久 | 超碰96在线 | 天堂资源网 | 黄网在线播放 | 国产宾馆实践打屁股91 | 91免费在线视频 | 日韩人成 | 欧美自拍区 | 久久久精品免费 | 欧美区国产区 | 人妻夜夜爽天天爽三区麻豆av网站 | 精品人妻一区二区三区蜜桃 | 国产视频黄色 | 男女午夜爽爽 | 小明天天看 | 播色屋 | 久久疯狂做爰流白浆xx | 国产精品无码久久久久久 | 五月激情综合 | 67194av | www夜夜 | 特黄三级 | 欧美三级午夜理伦三级 | av中文字幕免费观看 | 自慰无码一区二区三区 | 啊灬啊灬啊灬秀婷 | 实拍女处破www免费看 | 亚洲综合久久久 |