gpt4 book ai didi

go - 这是在 go 中使用 channel 的正确方法吗?

转载 作者:数据小太阳 更新时间:2023-10-29 03:23:25 26 4
gpt4 key购买 nike

在这里,我尝试遍历 res 并为每个项目启动一个 goroutine。在每个 goroutine 中,我再次在缓冲 channel 中启动 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
}

最佳答案

close(c)close(ch) 移到 for ... range 循环之前。

一旦缓冲的、未关闭的 channel 达到 len(ch) == 0for e := range ch { ... } 将永远阻塞 - - 等待另一个 goroutine 向 channel 执行发送语句。关闭表示不会有更多的元素发送到 channel (任何发送到关闭的 channel 都会导致 panic ),并且会导致 for e := range ch {...} 循环当 channel 为空时结束。

It gives following error panic: send on closed channel

发送到一个关闭的 channel 会导致 panic 。您收到此错误是因为您的 main goroutine 在发送到另一个 goroutine 之前到达了关闭语句。

对于如何处理这个问题,您有多种选择。一种是使用 sync.WaitGroup在关闭 channel 之前等待将发送到 channel 的所有 goroutines 完成。像这样的东西:

go mapSubmission(&sub, val, c)
go mapUser(&sub, val, c)
go mapFiles(&sub, val, c)
// ...
wg.Wait()
close(c)
for element := range c {
// ...

另一种方法是跟踪您期望在 channel 上发送的数量,删除 for e := range ch {...} 循环并将它们替换为将执行接收运算符的循环在 channel 上正确的次数。在这种情况下,如果您愿意,您也可以使用无缓冲 channel 而不是缓冲 channel 。如果您知道调用接收操作符多少次,则不需要 for e := range ch {...},也不需要关闭 channel 。

另一种方法是根本不使用 channel 。因为你所做的只是打印到标准输出,你可以将打印移动到 goroutines 内部,并使用 sync.WaitGroup 来确保你的 main goroutine 不会退出直到你的函数 goroutines 打印了它们的输出。

关于go - 这是在 go 中使用 channel 的正确方法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48998218/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com