我是Golang并發的新手,一直在努力理解下面提到的這段代碼。我目睹了一些我無法解釋為什么會發生的事情:for i <= 100000 {在 main 函數中 使用小于等于 100000 的 i 時,它有時會為 nResults 和 countWrites 打印不同的值(在最后兩個語句中)fmt.Printf("number of result writes %d\n", nResults) fmt.Printf("Number of job writes %d\n", jobWrites)當我使用超過 1000000 時,它給出panic: send on closed channel我如何確保發送給作業的值不在關閉的通道上,并且稍后在結果中收到所有值后我們可以關閉通道而不會出現死鎖?package mainimport ( "fmt" "sync")func worker(wg *sync.WaitGroup, id int, jobs <-chan int, results chan<- int, countWrites *int64) { defer wg.Done() for j := range jobs { *countWrites += 1 go func(j int) { if j%2 == 0 { results <- j * 2 } else { results <- j } }(j) }}func main() { wg := &sync.WaitGroup{} jobs := make(chan int) results := make(chan int) var i int = 1 var jobWrites int64 = 0 for i <= 10000000 { go func(j int) { if j%2 == 0 { i += 99 j += 99 } jobWrites += 1 jobs <- j }(i) i += 1 } var nResults int64 = 0 for w := 1; w < 1000; w++ { wg.Add(1) go worker(wg, w, jobs, results, &nResults) } close(jobs) wg.Wait() var sum int32 = 0 var count int64 = 0 for r := range results { count += 1 sum += int32(r) if count == nResults { close(results) } } fmt.Println(sum) fmt.Printf("number of result writes %d\n", nResults) fmt.Printf("Number of job writes %d\n", jobWrites)}
1 回答

慕村9548890
TA貢獻1884條經驗 獲得超4個贊
您的代碼中有很多問題。
在關閉的頻道上發送
使用 Go 通道的一個一般原則是
不要從接收端關閉通道,如果通道有多個并發發送者則不要關閉通道
您的解決方案很簡單:不要有多個并發發件人,然后您可以從發件人端關閉頻道。
與其為添加到通道的每個作業啟動數百萬個單獨的 goroutine,不如運行一個執行整個循環的 goroutine 以將所有作業添加到通道。并在循環后關閉通道。工作人員將盡可能快地使用通道。
通過修改多個 goroutine 中的共享變量來進行數據競爭
您在不采取特殊步驟的情況下修改兩個共享變量:
nResults
,您將其傳遞給countWrites *int64
工作人員中的。i
jobs
在寫入作業通道的循環中:您從多個 goroutines 向它添加 99,這使得它無法預測您實際向通道寫入了多少值
要解決 1,有很多選項,包括使用sync.Mutex
.?但是,由于您只是添加它,所以最簡單的解決方案是使用atomic.AddInt64(countWrites, 1)
而不是*countWrites += 1
要解決 2,不要在每次寫入通道時使用一個 goroutine,而是在整個循環中使用一個 goroutine(見上文)
- 1 回答
- 0 關注
- 90 瀏覽
添加回答
舉報
0/150
提交
取消