我正在研究a blog上有关使用go例程的时间的信息,我看到了下面粘贴的示例(从61行到65行)。但是我没有达到这里使用channel的目的。
似乎他正在迭代通道以检索go-routine中的msg。 但是为什么不直接使用字符串数组呢?
58 func findConcurrent(goroutines int, topic string, docs []string) int {
59 var found int64
60
61 ch := make(chan string, len(docs))
62 for _, doc := range docs {
63 ch <- doc
64 }
65 close(ch)
66
67 var wg sync.WaitGroup
68 wg.Add(goroutines)
69
70 for g := 0; g < goroutines; g++ {
71 go func() {
72 var lFound int64
73 for doc := range ch {
74 items, err := read(doc)
75 if err != nil {
76 continue
77 }
78 for _, item := range items {
79 if strings.Contains(item.Description, topic) {
80 lFound++
81 }
82 }
83 }
84 atomic.AddInt64(&found, lFound)
85 wg.Done()
86 }()
87 }
88
89 wg.Wait()
90
91 return int(found)
92 }
答案 0 :(得分:2)
此代码提供了在多个goRoutine之间分配工作(在文档内查找字符串)的方法的示例。基本上,代码是从goroutines
开始,然后向其提供文档以通过渠道进行搜索。
但是为什么不直接使用字符串数组呢?
可以使用字符串数组和变量(将其称为count
)来跟踪您要处理的数组中的哪个项目。您将有一些类似的代码(有点冗长地演示了一点):
for {
if count > len(docarray) {
break;
}
doc := docarray[count]
count++
// Process the document
}
但是您会遇到同步问题。例如,如果两个go例程(在不同的处理器内核上运行)同时到达if count > len(docarray)
,会发生什么情况?如果没有防止这种情况发生的方法,它们可能都将最终处理片中的同一项目(并且可能会跳过下一个元素,因为它们都运行count++
)。
流程的同步非常复杂,问题很难调试。使用通道会给您隐藏很多此类复杂性,并使您的代码按预期工作的可能性更大(它不能解决所有问题;请注意在示例代码中使用atomic.AddInt64(&found, lFound)
来防止可能发生的另一个潜在问题多个go例程同时写入一个变量的结果)。
答案 1 :(得分:0)
作者似乎只是在使用一个人为设计的示例来说明渠道是如何工作的。也许他想出一个更现实的例子。但是他确实说:
注意:编写并发版本的add时,可以采用几种方法和选项。现在不要挂在我的特定实现上。如果您的可读性更好的版本具有相同或更好的性能,我希望与您分享。
因此,很明显,他并没有试图为这份工作编写最好的代码,只是为了说明他的观点。