在下面的代碼中,我不明白為什么“Worker”方法似乎退出而不是從“in”輸入通道中提取值并處理它們。
我原以為它們只會在消耗了來自輸入通道“in”的所有輸入并處理它們后才會回傳
package main
import (
"fmt"
"sync"
)
type ParallelCallback func(chan int, chan Result, int, *sync.WaitGroup)
type Result struct {
i int
val int
}
func Worker(in chan int, out chan Result, id int, wg *sync.WaitGroup) {
for item := range in {
item *= item // returns the square of the input value
fmt.Printf("=> %d: %d\n", id, item)
out <- Result{item, id}
}
wg.Done()
fmt.Printf("%d exiting ", id)
}
func Run_parallel(n_workers int, in chan int, out chan Result, Worker ParallelCallback) {
wg := sync.WaitGroup{}
for id := 0; id < n_workers; id {
fmt.Printf("Starting : %d\n", id)
wg.Add(1)
go Worker(in, out, id, &wg)
}
wg.Wait() // wait for all workers to complete their tasks
close(out) // close the output channel when all tasks are completed
}
const (
NW = 4
)
func main() {
in := make(chan int)
out := make(chan Result)
go func() {
for i := 0; i < 100; i {
in <- i
}
close(in)
}()
Run_parallel(NW, in, out, Worker)
for item := range out {
fmt.Printf("From out : %d: %d", item.i, item.val)
}
}
輸出是
Starting : 0
Starting : 1
Starting : 2
Starting : 3
=> 3: 0
=> 0: 1
=> 1: 4
=> 2: 9
fatal error: all goroutines are asleep - deadlock!
uj5u.com熱心網友回復:
致命錯誤:所有 goroutine 都處于睡眠狀態 - 死鎖!
完整的錯誤顯示了每個 goroutine 被“卡住”的位置。 如果你在操場上運行這個,它甚至會顯示你的行號。這使我很容易診斷。
您Run_parallel在maingroutine 中運行,因此在main可以讀取之前out,Run_parallel必須回傳。在Run_parallel可以回傳之前,它必須wg.Wait()。但在工人打電話之前wg.Done(),他們必須寫信給out。這就是導致死鎖的原因。
一種解決方案很簡單:只需Run_parallel在其自己的 Goroutine 中并發運行即可。
go Run_parallel(NW, in, out, Worker)
現在,mainrange over out,等待outs 關閉以表示完成。 Run_parallel等待工人與wg.Wait(),工人將范圍in。所有的作業都會完成,程式不會結束,直到它全部完成。( https://go.dev/play/p/oMrgH2U09tQ )
uj5u.com熱心網友回復:
解決方案 :
Run_parallel 必須在它自己的 goroutine 中運行:
package main
import (
"fmt"
"sync"
)
type ParallelCallback func(chan int, chan Result, int, *sync.WaitGroup)
type Result struct {
id int
val int
}
func Worker(in chan int, out chan Result, id int, wg *sync.WaitGroup) {
defer wg.Done()
for item := range in {
item *= 2 // returns the double of the input value (Bogus handling of data)
out <- Result{id, item}
}
}
func Run_parallel(n_workers int, in chan int, out chan Result, Worker ParallelCallback) {
wg := sync.WaitGroup{}
for id := 0; id < n_workers; id {
wg.Add(1)
go Worker(in, out, id, &wg)
}
wg.Wait() // wait for all workers to complete their tasks
close(out) // close the output channel when all tasks are completed
}
const (
NW = 8
)
func main() {
in := make(chan int)
out := make(chan Result)
go func() {
for i := 0; i < 10; i {
in <- i
}
close(in)
}()
go Run_parallel(NW, in, out, Worker)
for item := range out {
fmt.Printf("From out [%d]: %d\n", item.id, item.val)
}
println("- - - All done - - -")
}
uj5u.com熱心網友回復:
解決方案的替代配方:
在該替代公式中,沒有必要將 Run_parallel 作為 goroutine 啟動(它會觸發自己的 goroutine)。我更喜歡第二種解決方案,因為它自動化了 Run_parallel() 必須與主函式并行運行的事實。此外,出于同樣的原因,它更安全,更不容易出錯(無需記住使用 go 關鍵字運行 Run_parallel)。
package main
import (
"fmt"
"sync"
)
type ParallelCallback func(chan int, chan Result, int, *sync.WaitGroup)
type Result struct {
id int
val int
}
func Worker(in chan int, out chan Result, id int, wg *sync.WaitGroup) {
defer wg.Done()
for item := range in {
item *= 2 // returns the double of the input value (Bogus handling of data)
out <- Result{id, item}
}
}
func Run_parallel(n_workers int, in chan int, out chan Result, Worker ParallelCallback) {
go func() {
wg := sync.WaitGroup{}
defer close(out) // close the output channel when all tasks are completed
for id := 0; id < n_workers; id {
wg.Add(1)
go Worker(in, out, id, &wg)
}
wg.Wait() // wait for all workers to complete their tasks *and* trigger the -differed- close(out)
}()
}
const (
NW = 8
)
func main() {
in := make(chan int)
out := make(chan Result)
go func() {
defer close(in)
for i := 0; i < 10; i {
in <- i
}
}()
Run_parallel(NW, in, out, Worker)
for item := range out {
fmt.Printf("From out [%d]: %d\n", item.id, item.val)
}
println("- - - All done - - -")
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/373880.html
