Golang Channel

主軸

  • Golang 使用 Goroutines 和 Channels 實現了 CSP(Communicating Sequential Processes) 模型 , Channel 主要是溝通和同步機制的角色

主要範例

Channel 特性

  • Channels 於 Goroutine 中是安全的
  • Channels 用於 Goroutine 之間傳遞訊息
  • 提供 FIFO 特性語法使用
  • Channels 可以實現 Goroutine 阻塞/非阻塞

Worker Pool

實作簡單 simple task queue with just channels

func main() {
	// Buffered channel 建立緩存區 channel
	ch := make(chan Task, 3)
	
	// Run fixed number of workers 執行固定數量的 worker
	for i := 0; i < numWrokers; i++ {
		go worker(ch)
	}
	
	// Send tasks to workers 傳送所有task給worker
	hellaTasks := getTasks()
	
	for _, task := range hellaTasks {
		taskCh <- task
	}
}

func worker(ch) {
	for {
		// Receive task 接收 task
		task := <- taskCh
		process(task)
	}
}

解析 Channels

對應以上範例

Making channels 建立 channels

ch := make(chan Task, 3)

  1. 建立可緩存三個Task的Buffered Channel
  2. make chan 申請初始化於 heap 中結構是hchan struct 回傳的是一個 ptr
  3. 由於回傳的是 ptr 因此 channel 可以於 func 之間傳遞

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

使用 channels

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

接收者&發送者如何運作

  1. G1 是發送者 G2 是 worker
  2. G1 取出第一個 Task 透過 Channel 發送給 G2,獲取鎖並將值送去通道,排隊的實際上是原本值的 copy
  3. G2 收到 G1 來的值,並且獲取鎖同時 copy 接收到值
  4. 傳輸都是 copy 的因此都是安全的,同時 Channel 保護機制使用 Mutex,沒有任何資源是共享的,值也是 copy 的

阻塞/非阻塞如何運作

假設 G1 持續發送,G2 處理需要比較長時間,此時 Channel Queue滿了,G1 執行將會暫停

  1. 暫停的情況,會發生在 runtime 調度時
  2. Goroutines are user-space threads, created and managed by the Go runtime, not the OS. These are lightweight compared to OS threads w.r.t. research consumption and scheduling overhead.
  3. Go scheduler is a M:N scheduler: few OS threads and N goroutines; and scheduler is responsible to schedule the goroutines on limited number of OS threads.
暫停 Goroutines

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

When a goroutine needs to be paused, chan calls into the scheduler to park G1, what scheduler does is to change G1 from running to waiting. And schedule another goroutine on the OS thread.

  • This is good for perf. We haven’t stopped the OS thread but scheduled another goroutine by context switching. This is not expensive.
  • We need to resume the paused goroutine once the channel is not full anymore.
恢復 Goroutines

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

  • Waiting goroutine struct has a pointer to the element it is waiting on.
  • G1 created a sudog for itself, puts it in the channel’s wait queue. Sudog will be used to resume the G1 in the future.
  • What G2 does when the channel is not full anymore is to pop off the sudog. G1 is set runnable again. The runtime schedules G1 again and G1 resumes.

(Also explains the case what happens when G2 needs to be parked and resumed again.)

直接發送

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

When G1 finally runs, it needs to acquire the lock. But the runtime is actually is so much smarter to make this less costly. Runtime can copy directly to the receiver stack. G1 writes directly to G2’s stack and doesn’t have to acquire any locks.

On resuming, G2 does not need to acquire channel lock and manipulate the buffer. This also means one fewer memory copy.

Unbuffered channels or select?

Not in the scope of this talk. The Go runtime is written is Go and you read the source code to learn.

Channels 相關特性

  • chan IO 極限 10,000,000,單次 PUT,GET 耗時大約 100 ns/op

資源參考

understanding-channels-kavya-joshi