为什么在此函数中使用通道?
Why using channel in this function?
我正在研究a blog关于使用go-routines的时机,我看到下面粘贴的例子,从第61行到第65行。但是我不明白这里使用通道的目的。
看来他正在迭代通道以检索 go-routine 中的消息。
但是为什么不直接使用字符串数组呢?
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 }
作者似乎只是在用一个人为的例子来说明通道的工作原理。也许他最好想出一个更现实的例子。但他确实说:
Note: There are several ways and options you can take when writing a concurrent version of add. Don’t get hung up on my particular implementation at this time. If you have a more readable version that performs the same or better I would love for you to share it.
所以很明显,他并没有试图为这项工作编写最好的代码,只是为了说明他的观点。
此代码提供了在多个 goRoutine 之间分配工作(在文档中查找字符串)的方法示例。基本上,代码开始 goroutines
并向他们提供文档以通过频道进行搜索。
But why not directly using string array?
可以使用一个字符串数组和一个变量(我们称它为 count
)来跟踪您在数组中进行的操作。你会有一些代码(有点长篇大论来证明一个观点):
for {
if count > len(docarray) {
break;
}
doc := docarray[count]
count++
// Process the document
}
但是你会遇到同步问题。例如,如果两个 go 例程(运行ning 在不同的处理器内核上)同时到达 if count > len(docarray)
会发生什么?如果没有任何东西来阻止这种情况,他们可能最终都会处理切片中的相同项目(并且可能会跳过下一个元素,因为他们都 运行 count++
)。
进程同步很复杂,问题很难调试。使用通道向您隐藏了很多这种复杂性,并使您的代码更有可能按预期工作(它不能解决所有问题;请注意在示例代码中使用 atomic.AddInt64(&found, lFound)
以防止另一个潜在的问题多个 go 例程同时写入变量的结果)。
我正在研究a blog关于使用go-routines的时机,我看到下面粘贴的例子,从第61行到第65行。但是我不明白这里使用通道的目的。
看来他正在迭代通道以检索 go-routine 中的消息。 但是为什么不直接使用字符串数组呢?
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 }
作者似乎只是在用一个人为的例子来说明通道的工作原理。也许他最好想出一个更现实的例子。但他确实说:
Note: There are several ways and options you can take when writing a concurrent version of add. Don’t get hung up on my particular implementation at this time. If you have a more readable version that performs the same or better I would love for you to share it.
所以很明显,他并没有试图为这项工作编写最好的代码,只是为了说明他的观点。
此代码提供了在多个 goRoutine 之间分配工作(在文档中查找字符串)的方法示例。基本上,代码开始 goroutines
并向他们提供文档以通过频道进行搜索。
But why not directly using string array?
可以使用一个字符串数组和一个变量(我们称它为 count
)来跟踪您在数组中进行的操作。你会有一些代码(有点长篇大论来证明一个观点):
for {
if count > len(docarray) {
break;
}
doc := docarray[count]
count++
// Process the document
}
但是你会遇到同步问题。例如,如果两个 go 例程(运行ning 在不同的处理器内核上)同时到达 if count > len(docarray)
会发生什么?如果没有任何东西来阻止这种情况,他们可能最终都会处理切片中的相同项目(并且可能会跳过下一个元素,因为他们都 运行 count++
)。
进程同步很复杂,问题很难调试。使用通道向您隐藏了很多这种复杂性,并使您的代码更有可能按预期工作(它不能解决所有问题;请注意在示例代码中使用 atomic.AddInt64(&found, lFound)
以防止另一个潜在的问题多个 go 例程同时写入变量的结果)。