最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Golang通道的無(wú)阻塞讀寫的方法示例

 更新時(shí)間:2018年11月04日 16:39:23   作者:shitaibin  
這篇文章主要介紹了Golang通道的無(wú)阻塞讀寫的方法示例,詳細(xì)的介紹了哪些情況會(huì)存在阻塞,以及如何使用select解決阻塞,非常具有實(shí)用價(jià)值,需要的朋友可以參考下

無(wú)論是無(wú)緩沖通道,還是有緩沖通道,都存在阻塞的情況,但其實(shí)有些情況,我們并不想讀數(shù)據(jù)或者寫數(shù)據(jù)阻塞在那里,有1個(gè)唯一的解決辦法,那就是使用select結(jié)構(gòu)。

這篇文章會(huì)介紹,哪些情況會(huì)存在阻塞,以及如何使用select解決阻塞。

阻塞場(chǎng)景

阻塞場(chǎng)景共4個(gè),有緩存和無(wú)緩沖各2個(gè)。

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

  1. 通道中無(wú)數(shù)據(jù),但執(zhí)行讀通道。
  2. 通道中無(wú)數(shù)據(jù),向通道寫數(shù)據(jù),但無(wú)協(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ù)都由于阻塞在通道操作而無(wú)法繼續(xù)向下執(zhí)行,最后報(bào)了死鎖錯(cuò)誤。

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

  1. 通道的緩存無(wú)數(shù)據(jù),但執(zhí)行讀通道。
  2. 通道的緩存已經(jīng)占滿,向通道寫數(shù)據(jù),但無(wú)協(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!
}

使用Select實(shí)現(xiàn)無(wú)阻塞讀寫

select是執(zhí)行選擇操作的一個(gè)結(jié)構(gòu),它里面有一組case語(yǔ)句,它會(huì)執(zhí)行其中無(wú)阻塞的那一個(gè),如果都阻塞了,那就等待其中一個(gè)不阻塞,進(jìn)而繼續(xù)執(zhí)行,它有一個(gè)default語(yǔ)句,該語(yǔ)句是永遠(yuǎn)不會(huì)阻塞的,我們可以借助它實(shí)現(xiàn)無(wú)阻塞的操作。

下面示例代碼是使用select修改后的無(wú)緩沖通道和有緩沖通道的讀寫,以下函數(shù)可以直接通過(guò)main函數(shù)調(diào)用,其中的Ouput的注釋是運(yùn)行結(jié)果,從結(jié)果能看出,在通道不可讀或者不可寫的時(shí)候,不再阻塞等待,而是直接返回。

// 無(wú)緩沖通道讀
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
}

// 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")
 }
}

// 無(wú)緩沖通道寫
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
}

// 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")
 }
}

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

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

使用定時(shí)器替代default可以解決這個(gè)問(wèn)題。比如,我給通道讀寫數(shù)據(jù)的容忍時(shí)間是500ms,如果依然無(wú)法讀寫,就即刻返回,修改一下會(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

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • golang中validator包的使用教程

    golang中validator包的使用教程

    Validator 實(shí)際上是一個(gè)驗(yàn)證工具,屬于 golang 的第三方包,這個(gè)包中使用了各種反射技巧來(lái)提供了各種校驗(yàn)和約束數(shù)據(jù)的方式方法,下面就跟隨小編一起來(lái)學(xué)習(xí)一下validator包的使用吧
    2023-09-09
  • Go開發(fā)go-optioner工具實(shí)現(xiàn)輕松生成函數(shù)選項(xiàng)模式代碼

    Go開發(fā)go-optioner工具實(shí)現(xiàn)輕松生成函數(shù)選項(xiàng)模式代碼

    go-optioner?是一個(gè)在?Go?代碼中生成函數(shù)選項(xiàng)模式代碼的工具,可以根據(jù)給定的結(jié)構(gòu)定義自動(dòng)生成相應(yīng)的選項(xiàng)代碼,下面就來(lái)聊聊go-optioner是如何使用的吧
    2023-07-07
  • go語(yǔ)言實(shí)現(xiàn)mqtt協(xié)議的實(shí)踐

    go語(yǔ)言實(shí)現(xiàn)mqtt協(xié)議的實(shí)踐

    MQTT是一個(gè)基于客戶端-服務(wù)器的消息發(fā)布/訂閱傳輸協(xié)議。本文主要介紹了go語(yǔ)言實(shí)現(xiàn)mqtt協(xié)議的實(shí)踐,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • Go語(yǔ)言泛型打造優(yōu)雅的切片工具庫(kù)

    Go語(yǔ)言泛型打造優(yōu)雅的切片工具庫(kù)

    泛型是一種編程范式,允許開發(fā)者在編寫代碼時(shí)定義通用的類型參數(shù),而不是具體的類型,本文將使用泛型實(shí)現(xiàn)打造優(yōu)雅的切片工具庫(kù),希望對(duì)大家有所幫助
    2025-02-02
  • Golang編譯器介紹

    Golang編譯器介紹

    今天小編就為大家分享一篇關(guān)于go語(yǔ)言編譯器的介紹,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-09-09
  • 一文帶你吃透Go語(yǔ)言中的原子操作

    一文帶你吃透Go語(yǔ)言中的原子操作

    原子操作是解決并發(fā)編程中共享數(shù)據(jù)訪問(wèn)問(wèn)題的一種常見機(jī)制,下面就來(lái)和大家深入介紹原子操作的原理、用法以及在解決并發(fā)問(wèn)題中的應(yīng)用,需要的可以參考一下
    2023-06-06
  • golang自帶的死鎖檢測(cè)并非銀彈的問(wèn)題小結(jié)

    golang自帶的死鎖檢測(cè)并非銀彈的問(wèn)題小結(jié)

    Go語(yǔ)言自帶的死鎖檢測(cè)機(jī)制并不萬(wàn)能,它只對(duì)用戶創(chuàng)建的協(xié)程進(jìn)行檢測(cè),并且在特定條件下可能會(huì)“失靈”,死鎖檢測(cè)的觸發(fā)時(shí)機(jī)和檢測(cè)內(nèi)容也有限制,因此不能完全避免死鎖問(wèn)題,為了預(yù)防死鎖,應(yīng)該在編寫代碼時(shí)提前進(jìn)行設(shè)計(jì)和測(cè)試,感興趣的朋友跟隨小編一起看看吧
    2025-01-01
  • go中的unsafe包及使用詳解

    go中的unsafe包及使用詳解

    Unsafe code是一種繞過(guò)go類型安全和內(nèi)存安全檢查的Go代碼。這篇文章主要介紹了go中的unsafe包,需要的朋友可以參考下
    2019-07-07
  • go運(yùn)算符對(duì)變量和值執(zhí)行操作示例詳解

    go運(yùn)算符對(duì)變量和值執(zhí)行操作示例詳解

    這篇文章主要為大家介紹了go運(yùn)算符對(duì)變量和值執(zhí)行操作示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • 基于go語(yǔ)言實(shí)現(xiàn)圖片驗(yàn)證碼的代碼示例

    基于go語(yǔ)言實(shí)現(xiàn)圖片驗(yàn)證碼的代碼示例

    這篇文章主要為大家詳細(xì)介紹了基于go語(yǔ)言實(shí)現(xiàn)圖片驗(yàn)證碼的代碼示例,文中的示例代碼簡(jiǎn)潔易懂,具有一定的借鑒價(jià)值,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-10-10

最新評(píng)論

铜山县| 金堂县| 邻水| 沂南县| 桑植县| 收藏| 芦溪县| 兴文县| 尖扎县| 凌源市| 江都市| 荣昌县| 青川县| 琼海市| 玉树县| 彰化县| 白城市| 龙泉市| 桐乡市| 廊坊市| 朔州市| 敦煌市| 巩留县| 施秉县| 广宁县| 贞丰县| 厦门市| 民权县| 大同县| 盈江县| 于都县| 瓦房店市| 平湖市| 景谷| 常山县| 高尔夫| 公安县| 南皮县| 陆丰市| 曲麻莱县| 泰和县|