日韩性视频-久久久蜜桃-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久久久噜噜噜熟女软件 | 又欲又污又肉又黄短文 | 色先锋在线 | 99久久国产宗和精品1上映 | 亚洲视频在线播放免费 | 波多野吉衣av在线 | 欧色av| 91精品国产91久久久久 | 天堂俺去俺来也www 欧美大片在线播放 | 男人天堂网在线 | 欧美第一页浮力影院 | 亚洲 欧美 变态 另类 综合 | 在线免费 | 青娱乐福利视频 | 色乱码一区二区三区网站 | 亚洲国产欧美一区二区三区深喉 | 天天操天天干天天爱 | 一区二区三区久久精品 | av无线看| 美女在线不卡 | 国产精品嫩草久久久久 | 国产主播啪啪 | 欧美日韩国 | 麻豆91精品91久久久 | 免费毛片大全 | 91theporn国产在线观看 | 伊人欧美在线 | 国产一区二区激情视频 | www日韩欧美 | 日女人网站| 韩日精品视频 | 欧美日韩国产精品 | 国产美女无遮挡免费视频 | 日韩电影在线一区二区 | 亚洲精品国产免费 | av2018| 国产美女91呻吟求 | 国产又大又长又粗 | 国产中文在线观看 | 91亚洲欧美激情 | 欧美成欧美va | 国产一区二区三区久久久 | 免费一级全黄少妇性色生活片 | 春色导航| 欧美成人亚洲 | 免费黄色av网站 | aaa亚洲精品 | 国产超碰自拍 | 欧美影视 | 日韩人妻精品无码一区二区三区 | 中国特级毛片 | 国产精品久久久久久久久毛片 | 我和我的太阳泰剧在线观看泰剧 | 成人黄色免费在线观看 | 日韩欧美字幕 | 久久久久久久久久福利 | 日韩av无码一区二区三区 | 精品久久久久久一区二区里番 | 吊侵犯の奶水授乳羞羞漫画 | 日韩tv | 五月天视频网站 | 人日人视频| 精品无码黑人又粗又大又长 | 日韩一级不卡 | 爱爱小视频免费看 | 在线观看日本一区二区 | tube国产麻豆| h部分肌肉警猛淫文 | 吊视频一区二区三区 | 亚洲一本在线 | 激情文学综合网 | 国产做爰免费观看视频 | 久操热线 | 亚洲色成人www永久在线观看 | 国产国语性生话播放 | 亚洲videos| 超碰在线观看91 | 免费的一级片 | 双性皇帝高h喷汁呻吟 | 91插插插永久免费 | 99国产精品99 | 亚洲成年人网站在线观看 | 欧美黄色大片免费观看 | 97久久免费视频 | 少妇做爰免费视看片 | 日韩亚洲精品在线 | 日韩久久一区二区三区 | 深夜视频一区二区 | 四虎国产精品成人免费入口 | 亚洲福利视频导航 | 你懂的视频在线播放 | 欧美一区在线观看视频 | 久艹视频在线观看 | 麻豆成人久久精品一区二区三区 | 亚洲色图视频在线观看 | 久草99 | 亚洲国产精品成人综合久久久 |