這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。有時候有這樣一種應用情境:需要等待多個事件到達,然後返回儘可能多的事件;如果沒有事件到達就阻塞等待。例如伺服器等待用戶端建立串連,或者等待用戶端資料等就有這種應用需求。在go語言裡,可以利用select原語和它的非阻塞(default)分支組合實現這個功能:
// 從ch擷取儘可能多的資料放到events裡,並返回實際數量;如果沒有資料就阻塞等待func wait(ch chan int, events []int) int { count := 0 for count < len(events) { select { case x := <-ch: events[count] = x count++ default: if count > 0 { return count } events[count] = <-ch count++ } } return count}
如果再加上退出檢查:
import "errors"func wait(ch chan int, exit chan bool, events []int) (int, error) { count := 0 for count < len(events) { select { case <-exit: return 0, errors.New("exit") case x := <-ch: events[count] = x count++ default: if count > 0 { return count, nil } select { case <-exit: return 0, errors.New("exit") case x := <-ch: events[count] = x count++ } } } return count, nil}
可以看到,這裡的實現有很多重複代碼,非常的冗長難讀。我們可以利用channel以下特性改寫一下:1.讀取或者寫入空channel時永久阻塞2.讀取一個已經關閉的channel立即返回空值
import "errors"var (CLOSED = make(chan int))func init() {close(CLOSED)}func pass(flag bool) chan int {if flag {return CLOSED}return nil}func wait(ch chan int, exit chan bool, events []int) (int, error) {count := 0LOOP:for count < len(events) {select {case <-exit:return 0, errors.New("exit")case x := <-ch:events[count] = xcount++case <-pass(count > 0):break LOOP}}return count, nil}
現在的實現就比較清晰簡潔易讀。