亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

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

發布時間:2020-07-28 15:20:15 來源:網絡 閱讀:171 作者:xiao_lili 欄目:編程語言

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

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

阻塞場景

阻塞場景共4個,有緩存和無緩沖各2個。

無緩沖通道的特點是,發送的數據需要被讀取后,發送才會完成,它阻塞場景:

  1. 通道中無數據,但執行讀通道。

  2. 通道中無數據,向通道寫數據,但無協程讀取。

// 場景1
func ReadNoDataFromNoBufCh() {
noBufCh := make(chan int)

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

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

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

ch <- 1
fmt.Println("write success no block")

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

注:示例代碼中的Output注釋代表函數的執行結果,每一個函數都由于阻塞在通道操作而無法繼續向下執行,最后報了死鎖錯誤。

有緩存通道的特點是,有緩存時可以向通道中寫入數據后直接返回,緩存中有數據時可以從通道中讀到數據直接返回,這時有緩存通道是不會阻塞的,它阻塞的場景是:

  1. 通道的緩存無數據,但執行讀通道。

  2. 通道的緩存已經占滿,向通道寫數據,但無協程讀。

// 場景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!
}

// 場景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實現無阻塞讀寫

select是執行選擇操作的一個結構,它里面有一組case語句,它會執行其中無阻塞的那一個,如果都阻塞了,那就等待其中一個不阻塞,進而繼續執行,它有一個default語句,該語句是永遠不會阻塞的,我們可以借助它實現無阻塞的操作。

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

// 無緩沖通道讀
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結構實現通道讀
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結構實現通道寫
func WriteChWithSelect(ch chan int) error {
select {
case ch <- 1:
return nil
default:
return errors.New("channel blocked, can not write")
}
}

使用Select+超時改善無阻塞讀寫

使用default實現的無阻塞通道阻塞有一個缺陷:當通道不可讀或寫的時候,會即可返回。實際場景,更多的需求是,我們希望,嘗試讀一會數據,或者嘗試寫一會數據,如果實在沒法讀寫,再返回,程序繼續做其它的事情。

使用定時器替代default可以解決這個問題。比如,我給通道讀寫數據的容忍時間是500ms,如果依然無法讀寫,就即刻返回,修改一下會是這樣:

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

結果就會變成超時返回:

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

文章同步發布: https://www.geek-share.com/detail/2752320764.html


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

龙游县| 弋阳县| 武夷山市| 稻城县| 泰兴市| 潜江市| 布拖县| 祁阳县| 津市市| 永年县| 永吉县| 东乡族自治县| 新邵县| 铁岭市| 北流市| 仙居县| 胶州市| 盐池县| 农安县| 上杭县| 惠来县| 盐津县| 凉城县| 南平市| 寻乌县| 鱼台县| 伊宁县| 达孜县| 黑水县| 汝阳县| 达拉特旗| 保德县| 元阳县| 惠州市| 介休市| 宁强县| 兴仁县| 寻乌县| 图片| 靖州| 建德市|