欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

golang channel讀取數據的幾種情況

 更新時間:2023年02月01日 09:53:06   作者:-_-void  
本文主要介紹了golang channel讀取數據的幾種情況,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

用var定義channel且不make

wg := sync.WaitGroup{}
var ch chan string

read := func() {
?? ?fmt.Println("reading")
?? ?s := <-ch
?? ?fmt.Println("read:", s)
?? ?wg.Done()
}

write := func() {
?? ?fmt.Println("writing")
?? ?s := "t"
?? ?ch <- s
?? ?fmt.Println("write:", s)
?? ?wg.Done()
}

wg.Add(2)
go read()
go write()

fmt.Println("waiting")
wg.Wait()

輸出:

waiting
writing
reading
fatal error: all goroutines are asleep - deadlock!

這種情況并不是報錯空指針,而是死鎖。加上make看看

用var定義channel且make

wg := sync.WaitGroup{}
var ch = make(chan string)

read := func() {
?? ?fmt.Println("reading")
?? ?s := <-ch
?? ?fmt.Println("read:", s)
?? ?wg.Done()
}

write := func() {
?? ?fmt.Println("writing")
?? ?s := "t"
?? ?ch <- s
?? ?fmt.Println("write:", s)
?? ?wg.Done()
}

wg.Add(2)
go read()
go write()

輸出

waiting
writing
reading
read: t
write: t

這種情況沒什么毛病,之所以先輸出的read,是因為IO機制。下面給寫加上for

直給寫操作加for

wg := sync.WaitGroup{}
var ch = make(chan string)

read := func() {
?? ?fmt.Println("reading")
?? ?s := <-ch
?? ?fmt.Println("read:", s)
?? ?wg.Done()
}

write := func() {
?? ?for {
?? ??? ?fmt.Println("writing")
?? ??? ?s := "t"
?? ??? ?ch <- s
?? ??? ?fmt.Println("write:", s)
?? ?}
?? ?wg.Done()
}

wg.Add(2)
go read()
go write()

fmt.Println("waiting")
wg.Wait()
fmt.Println("finish")

輸出

waiting
reading
writing
write: t
writing
read: t
fatal error: all goroutines are asleep - deadlock!

報錯說所有的協(xié)程都睡著,意思就是runtime發(fā)現(xiàn)沒有能拿來調度的協(xié)程了,報錯退出。如果是在大項目中,這里則會阻塞,runtime會調度其他可運行的協(xié)程。下面把for移到讀操作上。

直給讀操作加for

wg := sync.WaitGroup{}
var ch = make(chan string)

read := func() {
?? ?for {
?? ??? ?fmt.Println("reading")
?? ??? ?s := <-ch
?? ??? ?fmt.Println("read:", s)
?? ?}
?? ?wg.Done()
}

write := func() {
?? ?fmt.Println("writing")
?? ?s := "t"
?? ?ch <- s
?? ?fmt.Println("write:", s)
?? ?wg.Done()
}

wg.Add(2)
go read()
go write()

fmt.Println("waiting")
wg.Wait()
fmt.Println("finish")

輸出

waiting
reading
writing
write: t
read: t
reading
fatal error: all goroutines are asleep - deadlock!

跟上面現(xiàn)象基本一樣,不再贅述,然后給倆操作都加上for

讀寫都加for

wg := sync.WaitGroup{}
var ch = make(chan string)

read := func() {
?? ?for {
?? ??? ?fmt.Println("reading")
?? ??? ?s := <-ch
?? ??? ?fmt.Println("read:", s)
?? ?}
?? ?wg.Done()
}

write := func() {
?? ?for {
?? ??? ?fmt.Println("writing")
?? ??? ?s := "t"
?? ??? ?ch <- s
?? ??? ?fmt.Println("write:", s)
?? ?}
?? ?wg.Done()
}

wg.Add(2)
go read()
go write()

fmt.Println("waiting")
wg.Wait()
fmt.Println("finish")

輸出

waiting
writing
reading
read: t
write: t
writing
reading
read: t
reading
write: t
writing
write: t
writing
...

結果當然就是死循環(huán)了,這個很好理解。接下來才是本文的重點:讀數據的第二個參數。我們先保持其他的都不動,在讀的時候接收第二個返回值。

讀channel的第二個返回值

wg := sync.WaitGroup{}
var ch = make(chan string)

read := func() {
?? ?for {
?? ??? ?fmt.Println("reading")
?? ??? ?s, ok := <-ch
?? ??? ?fmt.Println("read:", s, ok)
?? ?}
?? ?wg.Done()
}

write := func() {
?? ?for {
?? ??? ?fmt.Println("writing")
?? ??? ?s := "t"
?? ??? ?ch <- s
?? ??? ?fmt.Println("write:", s)
?? ?}
?? ?wg.Done()
}

wg.Add(2)
go read()
go write()

fmt.Println("waiting")
wg.Wait()
fmt.Println("finish")

輸出

waiting
writing
reading
read: t true
reading
write: t
writing
write: t
writing
read: t true
reading
read: t true
reading
write: t
...

可以看出來,這第二個返回值是個bool類型,目前全都是true。那么什么時候會是false呢,把channel關上試試。為了更直觀,把字符串的長度一起輸出

關閉channel繼續(xù)讀

wg := sync.WaitGroup{}
var ch = make(chan string)

read := func() {
?? ?for {
?? ??? ?fmt.Println("reading")
?? ??? ?s, ok := <-ch
?? ??? ?fmt.Println("read:", len(s), s, ok)
?? ?}
?? ?wg.Done()
}

write := func() {
?? ?for i := 0; i < 5; i++ {
?? ??? ?fmt.Println("writing")
?? ??? ?s := "t"
?? ??? ?ch <- s
?? ??? ?fmt.Println("write:", s)
?? ?}
?? ?wg.Done()
?? ?close(ch)
}

wg.Add(2)
go read()
go write()

fmt.Println("waiting")
wg.Wait()
fmt.Println("finish")

輸出

waiting
writing
reading
read: 1 t true
reading
write: t
writing
write: t
writing
read: 1 t true
reading
read: 1 t true
reading
write: t
writing
write: t
writing
read: 1 t true
reading
read: 1 t true
reading
write: t
read: 0  false
reading
read: 0  false
reading
read: 0  false
...

接下來就是很規(guī)律的死循環(huán)了。這樣是不是可以猜測,從已經close的channle讀數據,會讀到該數據類型的零值,且第二個返回值為false?再試試給channel加個buffer,先寫完關上再開始讀

寫完然后關閉channel再開始讀

wg := sync.WaitGroup{}
var ch = make(chan string, 5)

read := func() {
?? ?for {
?? ??? ?fmt.Println("reading")
?? ??? ?s, ok := <-ch
?? ??? ?fmt.Println("read:", len(s), s, ok)
?? ?}
?? ?wg.Done()
}

write := func() {
?? ?for i := 0; i < 5; i++ {
?? ??? ?fmt.Println("writing")
?? ??? ?s := "t"
?? ??? ?ch <- s
?? ??? ?fmt.Println("write:", s)
?? ?}
?? ?wg.Done()
?? ?close(ch)
?? ?fmt.Println("closed")
}

wg.Add(2)
write()
go read()

fmt.Println("waiting")
wg.Wait()
fmt.Println("finish")

輸出

writing
write: t
writing
write: t
writing
write: t
writing
write: t
writing
write: t
closed
waiting
reading
read: 1 t true
reading
read: 1 t true
reading
read: 1 t true
reading
read: 1 t true
reading
read: 1 t true
reading
read: 0  false
reading
read: 0  false
reading
read: 0  false
...

我們把寫操作前的go關鍵字去了,并且在關閉channel之后加了log??梢院芮逦目吹?,先往channel里寫了5次,然后close了,之后才有wait及read的log。并且前5個ok是true,后面循環(huán)輸出false。現(xiàn)在我們可以得出結論當channel關閉且數據都讀完了,再讀數據會讀到該數據類型的零值,且第二個返回值為false。下面再套上select

加個select

wg := sync.WaitGroup{}
var ch = make(chan string, 5)

read := func() {
?? ?for {
?? ??? ?fmt.Println("reading")
?? ??? ?select {
?? ??? ?case s, ok := <-ch:
?? ??? ??? ?fmt.Println("read:", len(s), s, ok)
?? ??? ?}

?? ?}
?? ?wg.Done()
}

write := func() {
?? ?for i := 0; i < 5; i++ {
?? ??? ?fmt.Println("writing")
?? ??? ?s := "t"
?? ??? ?ch <- s
?? ??? ?fmt.Println("write:", s)
?? ?}
?? ?wg.Done()
?? ?close(ch)
?? ?fmt.Println("closed")
}

wg.Add(2)
write()
go read()

fmt.Println("waiting")
wg.Wait()
fmt.Println("finish")

輸出

writing
write: t
writing
write: t
writing
write: t
writing
write: t
writing
write: t
closed
waiting
reading
read: 1 t true
reading
read: 1 t true
reading
read: 1 t true
reading
read: 1 t true
reading
read: 1 t true
reading
read: 0  false
reading
read: 0  false
reading
read: 0  false
...

很明顯跟上面現(xiàn)象一致,如果忘了關閉channel呢?

channel未及時關閉

wg := sync.WaitGroup{}
var ch = make(chan string, 5)

read := func() {
?? ?for {
?? ??? ?fmt.Println("reading")
?? ??? ?select {
?? ??? ?case s, ok := <-ch:
?? ??? ??? ?fmt.Println("read:", len(s), s, ok)
?? ??? ?}

?? ?}
?? ?wg.Done()
}

write := func() {
?? ?for i := 0; i < 5; i++ {
?? ??? ?fmt.Println("writing")
?? ??? ?s := "t"
?? ??? ?ch <- s
?? ??? ?fmt.Println("write:", s)
?? ?}
?? ?wg.Done()
?? ?//close(ch)
?? ?//fmt.Println("closed")
}

wg.Add(2)
write()
go read()

fmt.Println("waiting")
wg.Wait()
fmt.Println("finish")

輸出

writing
write: t
writing
write: t
writing
write: t
writing
write: t
writing
write: t
waiting
reading
read: 1 t true
reading
read: 1 t true
reading
read: 1 t true
reading
read: 1 t true
reading
read: 1 t true
reading
fatal error: all goroutines are asleep - deadlock!

睡著了,然后報錯。跟上面情況一樣,如果是在大項目中,runtime會調度其他可運行的協(xié)程。最后來總結一下怎么操作才算優(yōu)(sao)雅(qi)。

總結

  • 對寫的一方來說,一定記著及時關閉channel,避免出現(xiàn)協(xié)程泄露。雖然它占得資源少,省點電不香么。
  • 對讀的一方來說,除非十分確定數據的個數,最好是用for來讀數據,省的在“管兒”里有“野數據”造成內存泄露。同時根據第二個返回值的真假來控制for循環(huán),避免出現(xiàn)“無效工作量”

到此這篇關于golang channel讀取數據的幾種情況的文章就介紹到這了,更多相關golang channel讀取內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Golang中的錯誤處理深入分析

    Golang中的錯誤處理深入分析

    Go錯誤處理類似C語言,沒有提供任何異常,以及類java語言使用的try/catch異常處理機制。Go異常處理僅簡化為預定義的Error類型,Go沒有提供異常處理機制,不能拋出類似許多其他語言的異常。相反,Golang集成了新的錯誤處理機制,如panic和recovery
    2023-01-01
  • Golang控制協(xié)程執(zhí)行順序方法詳解

    Golang控制協(xié)程執(zhí)行順序方法詳解

    這篇文章主要介紹了Golang控制協(xié)程執(zhí)行順序的方法,Golang的語法和運行時直接內置了對并發(fā)的支持。Golang里的并發(fā)指的是能讓某個函數獨立于其他函數運行的能力
    2022-11-11
  • 解決golang讀取http的body時遇到的坑

    解決golang讀取http的body時遇到的坑

    這篇文章主要介紹了解決golang讀取http的body時遇到的坑,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • golang NewRequest/gorequest實現(xiàn)http請求的示例代碼

    golang NewRequest/gorequest實現(xiàn)http請求的示例代碼

    本文主要介紹了golang NewRequest/gorequest實現(xiàn)http請求的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-08-08
  • Go語言error的設計理念及背景演化詳解

    Go語言error的設計理念及背景演化詳解

    這篇文章主要為大家介紹了Go語言error的設計理念及背景演化詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12
  • 簡單講解Go程序中使用MySQL的方法

    簡單講解Go程序中使用MySQL的方法

    這篇文章主要介紹了Go程序中使用MySQL的方法,需要使用第三方包來進行連接,需要的朋友可以參考下
    2015-10-10
  • GO中的條件變量sync.Cond詳解

    GO中的條件變量sync.Cond詳解

    條件變量是基于互斥鎖的,它必須基于互斥鎖才能發(fā)揮作用,條件變量的初始化離不開互斥鎖,并且它的方法有點也是基于互斥鎖的,這篇文章主要介紹了GO的條件變量sync.Cond,需要的朋友可以參考下
    2023-01-01
  • golang線程安全的map實現(xiàn)

    golang線程安全的map實現(xiàn)

    這篇文章主要介紹了golang線程安全的map實現(xiàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-03-03
  • go?zero微服務實戰(zhàn)處理每秒上萬次的下單請求

    go?zero微服務實戰(zhàn)處理每秒上萬次的下單請求

    這篇文章主要為大家介紹了go?zero微服務實戰(zhàn)處理每秒上萬次的下單請求示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-07-07
  • Go語言開發(fā)k8s之ConfigMap操作解析

    Go語言開發(fā)k8s之ConfigMap操作解析

    這篇文章主要為大家介紹了Go語言開發(fā)k8s之ConfigMap操作示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-06-06

最新評論