跳至主要內容
yomihon 書庫
整體狀況設定

鍵盤快捷鍵

⌘K / Ctrl K
搜尋
Esc
關閉搜尋或篩選
/
跳到導覽篩選(單鍵開啟時)
[
收合或展開側欄(單鍵開啟時)

關掉之後,/ 和 [ 都只會照瀏覽器原本的方式輸入;⌘K 與 Esc 不受影響。

設定
esc

↑↓ 選擇 ↵ 搜尋 esc 關閉

G05 固定數量的 worker

lesson檔案變更於
檔案變更於
類型
lesson
語言
zh-Hant
在 Obsidian 開啟留下自己的想法
檔案變更於
類型
lesson
語言
zh-Hant
在 Obsidian 開啟留下自己的想法

工作有一萬件,不必啟動一萬個 goroutine。固定三個 worker 從同一個 jobs channel 領取工作,便能把同時處理的工作數限制在三件。1

package main

import (
	"fmt"
	"slices"
	"sync"
)

func worker(jobs <-chan int, results chan<- int, wg *sync.WaitGroup) {
	defer wg.Done()
	for n := range jobs {
		results <- n * n
	}
}

func main() {
	jobs := make(chan int)
	results := make(chan int)
	var wg sync.WaitGroup
	const workers = 3
	wg.Add(workers)
	for i := 0; i < workers; i++ {
		go worker(jobs, results, &wg)
	}

	go func() {
		defer close(jobs)
		for _, n := range []int{1, 2, 3, 4, 5, 6} {
			jobs <- n
		}
	}()
	go func() {
		wg.Wait()
		close(results)
	}()

	var values []int
	for value := range results {
		values = append(values, value)
	}
	slices.Sort(values)
	fmt.Println(values)
}

等待者應該放在哪裡?

若把 wg.Wait() 與 close(results) 移回 main,放在接收迴圈之前,會發生什麼事?

查看執行流程

worker 卡在 results <- n*n,main 卻在等 worker 結束。兩邊互等,無法前進。

原程式讓協調者等待,main 同時接收。全部 worker 結束後,協調者才關閉結果 channel,讓接收迴圈退出。

工作順序與結果順序

哪個 worker 拿到哪件工作、哪個結果先抵達,都不固定。slices.Sort 只整理最後輸出,不改變執行順序:

[1 4 9 16 25 36]

這裡有三個 worker,另外還有送工作與等待收尾的 goroutine。「三個 worker」不等於整個程式只有三個 goroutine。

本例會收完全部結果。若只取一個就返回,送工作與送結果的地方都可能卡住,必須補上 G04 取消不再需要的工作 的退出方式。增加 channel 容量只能延後塞滿,不能取代取消。

作者標記的狀態 ready
設為 archived

設為 archived 之後,這裡不再有回到目前狀態的路。