Go 这是围棋中使用通道的正确方法吗?
在这里,我试图迭代Go 这是围棋中使用通道的正确方法吗?,go,Go,在这里,我试图迭代res并为每个项目启动一个goroutine。在每个goroutine中,我再次在一个缓冲通道中启动3个goroutine 运行此代码会阻止完成,不允许程序完成 func (aui *AssignmentUtilImpl) MapAssignmentSubmissionData(res []AssignmentSubmissionNode) []AssignmentSubmission { if res == nil { return nil
res
并为每个项目启动一个goroutine。在每个goroutine中,我再次在一个缓冲通道中启动3个goroutine
运行此代码会阻止完成,不允许程序完成
func (aui *AssignmentUtilImpl) MapAssignmentSubmissionData(res []AssignmentSubmissionNode) []AssignmentSubmission {
if res == nil {
return nil
}
submissions := []AssignmentSubmission{}
ch := make(chan string, len(res))
// map data
for _, val := range res {
go func(val AssignmentSubmissionNode) {
sub := AssignmentSubmission{}
c := make(chan string, 3)
go mapSubmission(&sub, val, c)
go mapUser(&sub, val, c)
go mapFiles(&sub, val, c)
sub.AssignmentId = val.AssignmentId
sub.ClassroomId = val.ClassroomId
for l := range c {
fmt.Println(l)
}
close(c)
submissions = append(submissions, sub)
ch <- "submission2: " + sub.Id
}(val)
}
for l := range ch {
fmt.Println(l)
}
close(ch)
return submissions
}
func mapFiles(sub *AssignmentSubmission, val AssignmentSubmissionNode, c chan string) {
for _, f := range val.Files {
file := resourceModule.File{}
mapstructure.Decode(f.Data, &file)
sub.Files = append(sub.Files, file)
}
c <- fmt.Sprintf("files: %d", len(sub.Files))
}
func mapUser(sub *AssignmentSubmission, val AssignmentSubmissionNode, c chan string) {
user := userModule.User{}
mapstructure.Decode(val.User.Data, &user)
sub.User = user
c <- "user: " + user.Id
}
func mapSubmission(sub *AssignmentSubmission, val AssignmentSubmissionNode, c chan string) {
mapstructure.Decode(val.Submission.Data, &sub)
c <- "submission1: " + sub.Id
}
func(aui*AssignmentUtimpl)MapAssignmentSubmissionData(res[]AssignmentSubmissionNode)[]AssignmentSubmissionSubmission{
如果res==nil{
归零
}
提交:=[]分配提交{}
ch:=制造(成串,透镜(分辨率))
//地图数据
对于u,val:=范围分辨率{
go func(val分配提交节点){
sub:=AssignmentSubmission{}
c:=制造(成串,3)
转到地图提交(&sub,val,c)
转到地图用户(&sub,val,c)
转到映射文件(&sub、val、c)
sub.AssignmentId=val.AssignmentId
sub.ClassroomId=val.ClassroomId
对于l:=范围c{
fmt.Println(左)
}
关闭(c)
提交=附加(提交,子)
ch将close(c)
和close(ch)
移动到for…range
循环之前
一旦缓冲的、未关闭的通道到达len(ch)==0
,e:=range ch{…}
的将永远阻塞--等待另一个goroutine执行发送到通道的send语句。关闭表示将不再有元素发送到通道(任何发送到关闭通道的操作都将导致死机),并将导致e:=range ch{…}
循环在通道为空时结束
它给出以下错误提示:在封闭通道上发送
发送到关闭的通道会导致死机。您收到此错误是因为您的main
goroutine在发送另一个goroutine之前到达了close语句
对于如何处理此问题,您有多个选项。其中一个选项用于在关闭频道之前等待将发送到频道的所有goroutine完成。类似于:
go mapSubmission(&sub, val, c)
go mapUser(&sub, val, c)
go mapFiles(&sub, val, c)
// ...
wg.Wait()
close(c)
for element := range c {
// ...
另一种方法是跟踪通道上预期的发送数,删除e:=range ch{…}的
循环并将其替换为一个循环,该循环将在通道上执行正确次数的接收运算符。在这种情况下,如果您愿意,您也可以使用无缓冲通道而不是缓冲通道。如果您知道调用接收运算符的次数,您不需要e:=范围ch{…}的
,无需关闭频道
另一种方法是根本不使用通道。因为您所做的只是打印到标准输出,所以您可以将打印移动到goroutines内部,并使用
sync.WaitGroup
来确保您的main
goroutine在您的函数goroutines打印输出之前不会退出。它给出以下错误panic:在封闭通道上发送
以某种方式使用通道比不使用通道花费更多的时间。Goroutines提供并发性。只有某些设计会提供并行性。通道需要协调,这总是有成本的。但如果速度慢得多,则可能会出现错误。