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

Golang通道阻塞情況與通道無阻塞實(shí)現(xiàn)小結(jié)

 更新時(shí)間:2024年04月19日 09:26:58   作者:TechLead?KrisChang  
本文主要介紹了Golang通道阻塞情況與通道無阻塞實(shí)現(xiàn)小結(jié),詳細(xì)解析了通道的類型、操作方法以及垃圾回收機(jī)制,從基礎(chǔ)概念到高級(jí)應(yīng)用,具有一定的參考價(jià)值,感興趣的可以了解一下

一、通道阻塞原理

在Go語言中,通道會(huì)在以下情況下發(fā)生阻塞:

  • 如果通道已滿,并且沒有協(xié)程在讀取通道中的數(shù)據(jù),那么任何試圖將數(shù)據(jù)寫入通道的協(xié)程都會(huì)被阻塞,直到有空間可用為止。
  • 如果通道為空,并且沒有協(xié)程在等待從通道中讀取數(shù)據(jù),那么任何試圖從通道中讀取數(shù)據(jù)的協(xié)程都會(huì)被阻塞,直到有數(shù)據(jù)可用為止。

二、通道阻塞場(chǎng)景

在channel中,無論是有緩存通道、無緩沖通道都存在阻塞的情況。阻塞場(chǎng)景共4個(gè),有緩存和無緩沖各2個(gè)。

2.1 無緩沖通道

無緩沖通道的特點(diǎn)是,發(fā)送的數(shù)據(jù)需要被讀取后,發(fā)送才會(huì)完成,它阻塞場(chǎng)景

  • 通道中無數(shù)據(jù),但執(zhí)行讀通道。
  • 通道中無數(shù)據(jù),向通道寫數(shù)據(jù),但無協(xié)程讀取。
// 場(chǎng)景1
func ReadNoDataFromNoBufCh() {
    noBufCh := make(chan int)

    <-noBufCh
    fmt.Println("read from no buffer channel success")

    // Output:
    // fatal error: all goroutines are asleep - deadlock!
}

// 場(chǎng)景2
func WriteNoBufCh() {
    ch := make(chan int)

    ch <- 1
    fmt.Println("write success no block")
    
    // Output:
    // fatal error: all goroutines are asleep - deadlock!
}

注:示例代碼中的Output注釋代表函數(shù)的執(zhí)行結(jié)果

每一個(gè)函數(shù)都由于阻塞在通道操作而無法繼續(xù)向下執(zhí)行,最后報(bào)了死鎖錯(cuò)誤。

2.2 有緩存通道

有緩存通道的特點(diǎn)是,有緩存時(shí)可以向通道中寫入數(shù)據(jù)后直接返回,緩存中有數(shù)據(jù)時(shí)可以從通道中讀到數(shù)據(jù)直接返回,這時(shí)有緩存通道是不會(huì)阻塞的,它阻塞場(chǎng)景是

  • 通道的緩存無數(shù)據(jù),但執(zhí)行讀通道。
  • 通道的緩存已經(jīng)占滿,向通道寫數(shù)據(jù),但無協(xié)程讀。
// 場(chǎng)景1
func ReadNoDataFromBufCh() {
    bufCh := make(chan int, 1)

    <-bufCh
    fmt.Println("read from no buffer channel success")

    // Output:
    // fatal error: all goroutines are asleep - deadlock!
}

// 場(chǎng)景2
func WriteBufChButFull() {
    ch := make(chan int, 1)
    // make ch full
    ch <- 100

    ch <- 1
    fmt.Println("write success no block")
    
    // Output:
    // fatal error: all goroutines are asleep - deadlock!
}

三、通道無阻塞讀寫

3.1 Select實(shí)現(xiàn)無阻塞讀寫

下面示例代碼是使用select修改后的無緩沖通道和有緩沖通道的讀寫,以下函數(shù)可以直接通過main函數(shù)調(diào)用;

// 1.select結(jié)構(gòu)實(shí)現(xiàn)通道讀
func ReadWithSelect(ch chan int) (x int, err error) {
    select {
    case x = <-ch:
        return x, nil
    default:
        return 0, errors.New("channel has no data")
    }
}

// 無緩沖通道讀
func ReadNoDataFromNoBufChWithSelect() {
    bufCh := make(chan int)

    if v, err := ReadWithSelect(bufCh); err != nil {
        fmt.Println(err)
    } else {
        fmt.Printf("read: %d\n", v)
    }

    // Output:
    // channel has no data
}

// 有緩沖通道讀
func ReadNoDataFromBufChWithSelect() {
    bufCh := make(chan int, 1)

    if v, err := ReadWithSelect(bufCh); err != nil {
        fmt.Println(err)
    } else {
        fmt.Printf("read: %d\n", v)
    }

    // Output:
    // channel has no data
}

// 2. select結(jié)構(gòu)實(shí)現(xiàn)通道寫
func WriteChWithSelect(ch chan int) error {
    select {
    case ch <- 1:
        return nil
    default:
        return errors.New("channel blocked, can not write")
    }
}

// 無緩沖通道寫
func WriteNoBufChWithSelect() {
    ch := make(chan int)
    if err := WriteChWithSelect(ch); err != nil {
        fmt.Println(err)
    } else {
        fmt.Println("write success")
    }

    // Output:
    // channel blocked, can not write
}

// 有緩沖通道寫
func WriteBufChButFullWithSelect() {
    ch := make(chan int, 1)
    // make ch full
    ch <- 100
    if err := WriteChWithSelect(ch); err != nil {
        fmt.Println(err)
    } else {
        fmt.Println("write success")
    }

    // Output:
    // channel blocked, can not write
}

注:示例代碼中的Output注釋代表函數(shù)的執(zhí)行結(jié)果

從結(jié)果能看出,在通道不可讀或者不可寫的時(shí)候,不再阻塞等待,而是直接返回。

3.2 使用Select+超時(shí)改善無阻塞讀寫

使用default實(shí)現(xiàn)的無阻塞通道阻塞有一個(gè)缺陷:當(dāng)通道不可讀或?qū)懙臅r(shí)候,會(huì)即可返回。實(shí)際場(chǎng)景,更多的需求是,我們希望嘗試讀一會(huì)數(shù)據(jù),或者嘗試寫一會(huì)數(shù)據(jù),如果實(shí)在沒法讀寫再返回,程序繼續(xù)做其它的事情。

使用定時(shí)器替代default可以解決這個(gè)問題,給通道增加讀寫數(shù)據(jù)的容忍時(shí)間,如果500ms內(nèi)無法讀寫,就即刻返回。示例代碼修改一下會(huì)是這樣:

func ReadWithSelect(ch chan int) (x int, err error) {
    timeout := time.NewTimer(time.Microsecond * 500)

    select {
    case x = <-ch:
        return x, nil
    case <-timeout.C:
        return 0, errors.New("read time out")
    }
}

func WriteChWithSelect(ch chan int) error {
    timeout := time.NewTimer(time.Microsecond * 500)

    select {
    case ch <- 1:
        return nil
    case <-timeout.C:
        return errors.New("write time out")
    }
}

結(jié)果就會(huì)變成超時(shí)返回:

read time out
write time out
read time out
write time out

四、總結(jié)

本篇文章介紹了在Go語言中,通道會(huì)在以下情況下發(fā)生阻塞:

  • 如果通道已滿,并且沒有協(xié)程在讀取通道中的數(shù)據(jù),那么任何試圖將數(shù)據(jù)寫入通道的協(xié)程都會(huì)被阻塞,直到有空間可用為止。
  • 如果通道為空,并且沒有協(xié)程在等待從通道中讀取數(shù)據(jù),那么任何試圖從通道中讀取數(shù)據(jù)的協(xié)程都會(huì)被阻塞,直到有數(shù)據(jù)可用為止。

以及解決阻塞的2種辦法:

  • 使用select的default語句,在channel不可讀寫時(shí),即可返回
  • 使用select+定時(shí)器,在超時(shí)時(shí)間內(nèi),channel不可讀寫,則返回

五、參考鏈接

到此這篇關(guān)于Golang通道阻塞情況與通道無阻塞實(shí)現(xiàn)小結(jié)的文章就介紹到這了,更多相關(guān)Golang通道阻塞情況與通道無阻塞內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

  • go開發(fā)中引用靜態(tài)庫.a文件的方法

    go開發(fā)中引用靜態(tài)庫.a文件的方法

    這篇文章主要介紹了go開發(fā)中引用靜態(tài)庫.a文件的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • Golang?PHP?數(shù)據(jù)綁定示例分析

    Golang?PHP?數(shù)據(jù)綁定示例分析

    這篇文章主要為大家介紹了Golang?PHP?數(shù)據(jù)綁定示例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • Go語言并發(fā)編程之互斥鎖Mutex和讀寫鎖RWMutex

    Go語言并發(fā)編程之互斥鎖Mutex和讀寫鎖RWMutex

    Go 語言中提供了很多同步工具,本文將介紹互斥鎖Mutex和讀寫鎖RWMutex的使用方法,想要具體了解的小伙伴,請(qǐng)參考下面文章詳細(xì)內(nèi)容,希望對(duì)你有所幫助
    2021-10-10
  • Golang 中的直接依賴和間接依賴管理詳解

    Golang 中的直接依賴和間接依賴管理詳解

    在 Golang 中,依賴管理是非常重要的,直接依賴是指項(xiàng)目代碼中明確引用的其他包的依賴,而間接依賴是指直接依賴所引用的其他包的依賴,這篇文章主要介紹了Golang 中的直接依賴和間接依賴管理,需要的朋友可以參考下
    2023-11-11
  • Go語言error的設(shè)計(jì)理念及背景演化詳解

    Go語言error的設(shè)計(jì)理念及背景演化詳解

    這篇文章主要為大家介紹了Go語言error的設(shè)計(jì)理念及背景演化詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • golang的time包:秒、毫秒、納秒時(shí)間戳輸出方式

    golang的time包:秒、毫秒、納秒時(shí)間戳輸出方式

    這篇文章主要介紹了golang的time包:秒、毫秒、納秒時(shí)間戳輸出方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Goland使用Go Modules創(chuàng)建/管理項(xiàng)目的操作

    Goland使用Go Modules創(chuàng)建/管理項(xiàng)目的操作

    這篇文章主要介紹了Goland使用Go Modules創(chuàng)建/管理項(xiàng)目的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-05-05
  • Go 并發(fā)讀寫 sync.map 詳細(xì)

    Go 并發(fā)讀寫 sync.map 詳細(xì)

    閱讀本文你將會(huì)明確 sync.Map 和原生 map +互斥鎖/讀寫鎖之間的性能情況。標(biāo)準(zhǔn)庫 sync.Map 雖說支持并發(fā)讀寫 map,但更適用于讀多寫少的場(chǎng)景,因?yàn)樗麑懭氲男阅鼙容^差,使用時(shí)要考慮清楚這一點(diǎn)。
    2021-10-10
  • 在Golang中使用http.FileServer返回靜態(tài)文件的操作

    在Golang中使用http.FileServer返回靜態(tài)文件的操作

    這篇文章主要介紹了在Golang中使用http.FileServer返回靜態(tài)文件的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Golang中的同步工具sync.WaitGroup詳解

    Golang中的同步工具sync.WaitGroup詳解

    這篇文章主要詳細(xì)為大家介紹了Golang中的同步工具sync.WaitGroup,文中有詳細(xì)的代碼示例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,一起跟隨小編過來看看吧
    2023-05-05

最新評(píng)論