我试图实现这个问题(所有goroutines都睡着了 - 死锁!) 这是代码的要点:
var workers = runtime.NumCPU()
func main() {
jobs := make(chan *myStruct, workers)
done := make(chan *myStruct, workers)
go produceWork(file_with_jobs, jobs)
for i := 0; i < runtime.NumCPU(); i++ {
go Worker(jobs, done)
}
consumeWork(done)
}
func produceWork(vf string, jobs chan *utils.DigSigEntries) {
defer close(jobs)
// load file with jobs
file, err := ini.LoadFile(vf)
// get data for processing
for data, _ := range file {
// ...
jobs <- &myStruct{data1, data2, data3, false}
}
}
func Worker(in, out chan *myStruct) {
for {
item, open := <-in
if !open {
break
}
process(item)
out <- item
}
// close(out) --> tried closing the out channel, but then not all items are processed
// though no panics occur.
}
func process(item *myStruct) {
//...modify the item
item.status = true
}
func consumeWork(done chan *myStruct) {
for val := range done {
if !val.status {
fmt.Println(val)
}
}
}
我主要是试图了解如何在不使用同步/等待的情况下实现这一点 - 只是纯粹的频道 - 这可能吗?这个例程的目标是让一个生产者加载由N个工人处理的项目 - 感谢任何指针/帮助。
答案 0 :(得分:0)
正如siritinga建议的那样,您可以使用第三个信令或计数器通道,例如signal chan boolean
,其中produceWork
goroutine会在每个作业输入jobs
频道之前添加一个值。因此,相同数量的值将传递给signal
jobs
:
func produceWork(vf string, jobs chan *utils.DigSigEntries, signal chan boolean) {
defer close(jobs)
// load file with jobs
file, err := ini.LoadFile(vf)
// get data for processing
for data, _ := range file {
// ...
signal <- true
jobs <- &myStruct{data1, data2, data3, false}
}
close(signal)
}
然后通过从signal
频道读取来开始消费。如果存在值,则可以确定将从out
通道读取值(一旦工作人员通过它)。如果signal
已关闭,则全部完成。我们可以关闭剩余的done
频道:
func consumeWork(done chan *myStruct, signal chan boolean) {
for _ := range signal {
val <- done
if !val.status {
fmt.Println(val)
}
}
close(done)
}
虽然这是可能的,但我不会真的推荐它。与使用sync.WaitGroup
时相比,它不会使代码更清晰。毕竟,signal
频道基本上只能用作计数器。 WaitGroup具有相同的目的,并且会更便宜。
但你的问题不在于如何解决问题,而在于是否可以用纯粹的渠道来解决问题。
答案 1 :(得分:0)
抱歉,我没注意到你想跳过/同步:/ 我会留下答案,也许有人正在寻找这个。
import (
"sync"
)
func main() {
jobs := make(chan *myStruct, workers)
done := make(chan *myStruct, workers)
var workerWg sync.WaitGroup // waitGroup for workers
var consumeWg sync.WaitGroup // waitGroup for consumer
consumeWg.Add(1) // add one active Consumer
for i := 0; i < runtime.NumCPU(); i++ {
go Worker(&workerWg, jobs, done)
workerWg.Add(1)
}
go consumeWork(&consumeWg, done)
produceWork(file_with_jobs, jobs)
close(jobs)
workerWg.Wait()
close(done)
consumeWg.Wait()
}
func produceWork(vf string, jobs chan *utils.DigSigEntries) {
// load file with jobs
file, err := ini.LoadFile(vf)
// get data for processing
for data, _ := range file {
// ...
jobs <- &myStruct{data1, data2, data3, false}
}
}
func Worker(wg *sync.WaitGroup, done chan *myStruct) {
defer wg.Done()
for job := range jobs {
result := process(job)
out <- result
}
// close(out) --> tried closing the out channel, but then not all items are processed
// though no panics occur.
}
func process(item *myStruct) {
//...modify the item
item.status = true
}
func consumeWork(wg *sync.WaitGroup, done chan *myStruct) {
defer wg.Done()
for val := range done {
if !val.status {
fmt.Println(val)
}
}
}