国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Golang > 正文

Golang通道的無阻塞讀寫的方法示例

2020-04-01 18:51:24
字體:
供稿:網(wǎng)友

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

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

阻塞場(chǎng)景

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

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

  1. 通道中無數(shù)據(jù),但執(zhí)行讀通道。
  2. 通道中無數(shù)據(jù),向通道寫數(shù)據(jù),但無協(xié)程讀取。
// 場(chǎng)景1func ReadNoDataFromNoBufCh() { noBufCh := make(chan int) <-noBufCh fmt.Println("read from no buffer channel success") // Output: // fatal error: all goroutines are asleep - deadlock!}// 場(chǎng)景2func 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ò)誤。

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

  1. 通道的緩存無數(shù)據(jù),但執(zhí)行讀通道。
  2. 通道的緩存已經(jīng)占滿,向通道寫數(shù)據(jù),但無協(xié)程讀。
// 場(chǎng)景1func 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)景2func 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)無阻塞讀寫

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

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

// 無緩沖通道讀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") }}// 無緩沖通道寫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í)改善無阻塞讀寫

使用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,如果依然無法讀寫,就即刻返回,修改一下會(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í)有所幫助,也希望大家多多支持VEVB武林網(wǎng)。


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 红桥区| 甘肃省| 饶阳县| 泗洪县| 宁乡县| 林州市| 滦南县| 莱州市| 同仁县| 江源县| 平阴县| 泸定县| 安龙县| 桑日县| 沂水县| 绿春县| 百色市| 岑溪市| 德保县| 清水河县| 乌苏市| 仁布县| 疏勒县| 双牌县| 曲麻莱县| 青州市| 博湖县| 江都市| 全州县| 资中县| 宜城市| 精河县| 新蔡县| 金堂县| 柘荣县| 太保市| 高尔夫| 柳河县| 桑植县| 平武县| 海南省|