18.8 協程(goroutine)與通道(channel)

出於性能考慮的建議:

實踐經驗表明,如果你使用並行運算獲得高於串行運算的效率:在協程內部已經完成的大部分工作,其開銷比創建協程和協程間通信還高。

1 出於性能考慮建議使用帶緩存的通道:

使用帶緩存的通道可以很輕易成倍提高它的吞吐量,某些場景其性能可以提高至10倍甚至更多。通過調整通道的容量,甚至可以嘗試着更進一步的優化其性能。

2 限制一個通道的數據數量並將它們封裝成一個數組:

如果使用通道傳遞大量單獨的數據,那麼通道將變成性能瓶頸。然而,將數據塊打包封裝成數組,在接收端解壓數據時,性能可以提高至10倍。

創建:ch := make(chan type,buf)

(1)如何使用for或者for-range遍歷一個通道:

for v := range ch {
    // do something with v
}

(2)如何檢測一個通道ch是否關閉:

//read channel until it closes or error-condition
for {
    if input, open := <-ch; !open {
        break
    }
    fmt.Printf("%s", input)
}

或者使用(1)自動檢測。

(3)如何通過一個通道讓主程序等待直到協程完成:

(信號量模式):

ch := make(chan int) // Allocate a channel.
// Start something in a goroutine; when it completes, signal on the channel.
go func() {
    // doSomething
    ch <- 1 // Send a signal; value does not matter.
}()
doSomethingElseForAWhile()
<-ch // Wait for goroutine to finish; discard sent value.

如果希望程序一直阻塞,在匿名函數中省略 ch <- 1即可。

(4)通道的工廠模板:以下函數是一個通道工廠,啓動一個匿名函數作爲協程以生產通道:

func pump() chan int {
    ch := make(chan int)
    go func() {
        for i := 0; ; i++ {
            ch <- i
        }
    }()
    return ch
}

(5)通道迭代器模板:

(6)如何限制併發處理請求的數量:參考章節14.11

(7)如何在多核CPU上實現並行計算:參考章節14.13

(8)如何終止一個協程:runtime.Goexit()

(9)簡單的超時模板:

timeout := make(chan bool, 1)
go func() {
    time.Sleep(1e9) // one second  
    timeout <- true
}()
select {
    case <-ch:
    // a read from ch has occurred
    case <-timeout:
    // the read from ch has timed out
}

(10)如何使用輸入通道和輸出通道代替鎖:

func Worker(in, out chan *Task) {
    for {
        t := <-in
        process(t)
        out <- t
    }
}

(11)如何在同步調用運行時間過長時將之丟棄:參考章節14.5 第二個變體

(12)如何在通道中使用計時器和定時器:參考章節14.5

(13)典型的服務器後端模型:參考章節14.4

鏈接

results matching ""

    No results matching ""