【发布时间】:2020-01-19 01:29:03
【问题描述】:
我正在学习 Go 中的并发性及其工作原理。
我想做什么?
- 循环遍历数据片段
- 为所需/需要的数据创建结构
- 为该结构创建通道
- 使用 go rutine 调用 worker func 并将该通道传递给该 rutine
- 使用来自通道的数据做一些处理
- 将处理后的输出设置回通道
- 在主线程中等待从我们启动的所有通道中获取输出
我尝试过的代码
package main
import (
"fmt"
"github.com/pkg/errors"
"time"
)
type subject struct {
Name string
Class string
StartDate time.Time
EndDate time.Time
}
type workerData struct {
Subject string
Class string
Result string
Error error
}
func main () {
// Creating test data
var subjects []subject
st,_ := time.Parse("01/02/2016","01/01/2015")
et,_ := time.Parse("01/02/2016","01/01/2016")
s1 := subject{Name:"Math", Class:"3", StartDate:st,EndDate:et }
s2 := subject{Name:"Geo", Class:"3", StartDate:st,EndDate:et }
s3 := subject{Name:"Bio", Class:"3", StartDate:st,EndDate:et }
s4 := subject{Name:"Phy", Class:"3", StartDate:st,EndDate:et }
s5 := subject{Name:"Art", Class:"3", StartDate:st,EndDate:et }
subjects = append(subjects, s1)
subjects = append(subjects, s2)
subjects = append(subjects, s3)
subjects = append(subjects, s4)
subjects = append(subjects, s5)
c := make(chan workerData) // I am sure this is not how I should be creating channel
for i := 0 ; i< len(subjects) ; i++ {
go worker(c)
}
for _, v := range subjects {
// Setting required data in channel
data := workerData{Subject:v.Name, Class:v.Class}
// set the data and start the routine
c <- data // I think this will update data for all the routines ? SO how should create separate channel for each routine
}
// I want to wait till all the routines set the data in channel and return the data from workers.
for {
select {
case data := <- c :
fmt.Println(data)
}
}
}
func worker (c chan workerData) {
data := <- c
// This can be any processing
time.Sleep(100 * time.Millisecond)
if data.Subject != "Math" {
data.Result = "Pass"
} else {
data.Error = errors.New("Subject not found")
}
fmt.Println(data.Subject)
// returning processed data and error to channel
c <- data
// Rightfully this closes channel and here after I get error send on Closed channel.
close(c)
}
Playgorund 链接 - https://play.golang.org/p/hs1-B1UR98r
我面临的问题
我不确定如何为每个数据项创建不同的通道。我目前正在做的方式将更新所有例程的通道数据。我想知道有没有办法为循环中的每个数据项创建不同的通道并将其传递给 go rutine。然后在 main rutine 中等待从所有通道的 rutines 中获取结果。
任何指针/帮助会很棒吗?如果有任何困惑,请随时发表评论。
【问题讨论】:
-
可能有一个小的(即 O(|CPU|),独立于 len(subjects) 工人池是正确的方法。但如果你真的希望每个主题有一个工人:做 不使用通道,您可以使用适当的数据直接启动工作程序。收集结果应始终使用 sync.Waitgroup 完成。有关并发性的示例,请参见 blog.golang.org。您尝试做什么do 看起来很可疑(即使这是一个简单的学习经历)。
-
您可能想要使用两个不同的通道,一个用于发送作业,另一个用于收集本示例中提到的结果 - gobyexample.com/worker-pools。如果您需要更多帮助,请告诉我。
-
如果你为每个值创建一个worker,为什么要在通道上发送值呢?只需将其作为参数传递。而且你永远不应该在同一个频道上输入和输出结果。