最近公司工作有點多,golang的select高階就這樣被拖沓啦,今天堅持把時間擠一擠,把吹的牛皮補上。
前一篇文章《golang併發模型:輕鬆入門select》介紹了select的作用和它的基本用法,這次介紹它的3個高階特性。
nil
的通道永遠阻塞
如何跳出for-select
select{}
阻塞
當case
上讀乙個通道時,如果這個通道是nil
,則該case
永遠阻塞。這個功能有1個妙用,select
通常處理的是多個通道,當某個讀通道關閉了,但不想select
再繼續關注此case
,繼續處理其他case
,把該通道設定為nil
即可。
下面是乙個合併程式等待兩個輸入通道都關閉後才退出的例子,就使用了這個特性。
func
combine
(inch1, inch2
chan
int)
chan
int out
case x, open :=
if!open
out}
// 當ch1和ch2都關閉是才退出
if inch1 ==
nil&& inch2 ==
nil}}(
)return out
}
break
在select
內的並不能跳出for-select
迴圈。看下面的例子,consume
函式從通道inch
不停讀資料,期待在inch
關閉後退出for-select
迴圈,但結果是永遠沒有退出。
func
consume
(inch
chan
int)
fmt.
printf
("read: %d\n"
, x)
} i++
} fmt.
println
("combine-routine exit"
)}
執行結果:
➜ go run x.go
for: 0
read: 0
for: 1
read: 1
for: 2
read: 2
for: 3
gen exit
for: 4
for: 5
for: 6
for: 7
for: 8
... // never stop
既然break
不能跳出for-select
,那怎麼辦呢?給你3個錦囊:
在滿足條件的case
內,使用return
,如果有結尾工作,嘗試交給defer
。
在select
外for
內使用break
挑出迴圈,如combine
函式。
使用goto
。
select{}
的效果等價於建立了1個通道,直接從通道讀資料:
ch :=
make
(chan
int)
但是,這個寫起來多麻煩啊!沒select{}
簡潔啊。
但是,永遠阻塞能有什麼用呢!?
當你開發乙個併發程式的時候,main
函式千萬不能在子協程幹完活前退出啊,不然所有的協程都被迫退出了,還怎麼提供服務呢?
比如,寫了個web服務程式,埠監聽、後端處理等等都在子協程跑起來了,main
函式這時候能退出嗎?
最後,介紹下我常用的select
場景:
給某個請求/處理/操作,設定超時時間,一旦超時時間內無法完成,則停止處理。
select
本色:多通道處理
golang併發模型:輕鬆入門流水線模型
golang併發模型:輕鬆入門流水線fan模式
golang併發模型:併發協程的優雅退出
golang併發模型:輕鬆入門select
如果這篇文章對你有幫助,不妨關注下我的github,有文章會收到通知。
golang中的CSP併發模型
1.相關概念 使用者態 當乙個程序在執行使用者自己的 時處於使用者執行態 使用者態 核心態 當乙個程序因為系統呼叫陷入核心 中執行時處於核心執行態 核心態 引入核心態防止使用者態的程式隨意的操作核心位址空間,具有一定的安全保護作用。這種保護模式是通過記憶體頁表操作等機制,保證程序間的位址空間不會相互...
golang 閒談併發
對於併發這個概念,我想大家都對它不會陌生,今天就從簡單的火車站賣票問題出發,來談談併發。首先宣告本文的 是golang 因為最近開始用的就是golang 對於其他的語言其實也是相通的,那麼正式開始正題吧,首先我們來看看,賣一張票,總票數就減一,一般來說我們會這麼寫 package main impo...
golang 併發實踐
golang 高併發主要是依靠sync包下的api實現,首先就是waitgroup 先說說waitgroup的用途 它能夠一直等到所有的goroutine執行完成,並且阻塞主線程的執行,直到所有的goroutine執行完成。waitgroup總共有三個方法 add delta int done wa...