channel用法和源碼


源碼分析https://mp.weixin.qq.com/s/eCwZMwGjU2yoXu6K2nGF3g

 

1 當chan用close關閉時,無論是有緩存的還是無緩存的,返回已緩沖數據或零值,如果重復用close關閉chan或對關閉的chan寫入值都會報錯,

https://blog.csdn.net/qq_41065919/article/details/107729571

https://www.cnblogs.com/pluse/p/12167537.html

struct{}類型好像只有一種具體實例即struct{}{},chan中如果有這種類型,只能寫入它的零值struct{}{},所以類型為struct{}的chan無論是寫入還是讀出都時零值,

func main()  {
    m := make(chan struct{}, 1)
    // 從空的m中一直讀取值會一直阻塞,所以會報死鎖的錯誤,all goroutines are asleep - deadlock!
    //b := <- m
    //fmt.Println(b)
    // 如果這里就關閉了協程,下面會直接輸出chan中的零值,而不會走default,
    //close(m)
    //m <- struct{}{}
    go func() {
        for{
            select {
            case a := <- m:
                fmt.Println(a)
                time.Sleep(time.Second)
            default:
                fmt.Println("chan為空,讀取的時候會阻塞")
                time.Sleep(time.Second)
            }
        }
    }()
    // 加這個是為了主協程等待里面的子協程,否則的話主協程直接執行完了,觀察不到子協程的具體輸出,
    time.Sleep(time.Second * 5)
}
View Code

a 如果close無緩存channel,

1> close前沒有因為寫入阻塞,則讀出的是channe里類型的零值,

2> 如果寫入阻塞了,則第一次讀出的是寫入的值,之后讀出的是零值,

func main()  {
    m := make(chan int)
    go func() {
        m <- 555
        // 這里雖然close了,但之后第一次讀出的仍是第一次寫入的值,
        close(m)
        // 保證close在讀之前
        time.Sleep(time.Second * 3)
    }()
    go func() {
        for{
            select {
            case a := <- m:
                if a != 0{
                    fmt.Println("第一次從channel中讀出的值為colse前寫入的值", a)
                } else{
                    fmt.Println("之后讀出的值為int類型的零值", a)
                }
                time.Sleep(time.Second)
            default:
                fmt.Println("chan為空,讀取的時候會阻塞")
                time.Sleep(time.Second)
            }
        }
    }()
    time.Sleep(time.Second * 4)
}
View Code

b 如果close有緩存channel,

1> close前沒有寫入,則讀出的是channel里類型的零值,

2> 如果close前寫入了,則會按隊列的順序把數據依次取出來,

func main()  {
    m := make(chan int, 3)
    m <- 111
    m <- 222
    close(m)
    go func() {
        for{
            select {
            case a := <- m:
                if a != 0{
                    fmt.Println("讀出的值是之前寫入的值", a)
                } else{
                    fmt.Println("之后讀出的值為int類型的零值", a)
                }
                time.Sleep(time.Second)
            default:
                fmt.Println("chan為空,讀取的時候會阻塞")
                time.Sleep(time.Second)
            }
        }
    }()
    time.Sleep(time.Second * 4)
}
View Code

待學習:https://i6448038.github.io/2019/04/11/go-channel/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM