func parallelSum (c chan int){
sum := 0
for i :=1 ; i< 100;i++{
go func(i int){
sum += i
}(i)
}
time.Sleep(1*time.Second)
c <- sum
}
我正在尝试学习并行功能,以加快诸如OpenMP之类的速度。这是Go中预期的总结并行循环的示例,此函数作为goroutine运行。
请注意,变量sum
在这里不是通道,这是否意味着for循环内的变量sum访问是阻塞操作?现在足够有效了吗?有更好的解决方案吗?
我知道通道功能是为此目的而设计的,下面的我显然错误的工具可以编译,但是有100个类似以下的运行时错误。
goroutine 4 [chan receive]:
main.parallelSumError(0xc0000180c0)
/home/tom/src/goland_newproject/main.go:58 +0xb4 //line 58 : temp := <-sum
created by main.main
/home/tom/src/goland_newproject/main.go:128 +0x2ca //line 128: go parallelSumError(pcr), the calling function
那么这是什么问题?似乎求和不是并行for循环的一个很好的例子,但实际上我希望知道如何在并行for循环内使用通道。
func parallelSum (c chan int){
sum := make(chan int)
for i :=1 ; i< 100;i++{
go func(i int){
temp := <- sum //error here why?
temp += i
sum <- temp
}(i)
}
time.Sleep(1*time.Second)
temp := <-sum
c <- temp
}
两者具有相同的主要功能
func main(){
pc := make(chan int)
go parallelSum(pc)
result = <- pc
fmt.Println("parallel result:", result)
}
答案 0 :(得分:1)
我不喜欢通过渠道对数字求和的想法。我宁愿使用诸如sync.Mutex
或atomic.AddUint64
之类的经典名称。但是,至少,我使您的代码正常工作。
我们无法将值从一个通道传递到另一个通道(我添加了temp
变量)。另外,还有sync.WaitGroup
和其他内容。
但是我仍然不喜欢代码的想法。
package main
import (
"fmt"
"sync"
)
func main() {
pc := make(chan int)
go parallelSum(pc)
result := <- pc
fmt.Println("parallel result:", result)
}
func parallelSum (c chan int){
sum := make(chan int)
wg := sync.WaitGroup{}
wg.Add(100)
for i :=1 ; i <= 100;i++{
go func(i int){
temp := <- sum
temp += i
wg.Done()
sum <- temp
}(i)
}
sum <- 0
wg.Wait()
temp := <- sum
c <- temp
}
答案 1 :(得分:1)
使用go例程(即go foo()
)时,最好通过内存共享使用通信。正如您所提到的,在此问题上,渠道是处理交流的通行方式。
对于您的特定应用,类似于OpenMP的并行和,最好检测CPU的数量并生成所需的例程:
package main
import (
"fmt"
"runtime"
)
func main() {
numCPU := runtime.NumCPU()
sumc := make(chan int, numCPU)
valuec := make(chan int)
endc := make(chan interface{}, numCPU)
// generate go routine per cpu
for i := 0; i < numCPU; i++ {
go sumf(sumc, valuec, endc)
}
// generate values and pass it through the channels
for i := 0; i < 100; i++ {
valuec <- i
}
// tell go routines to end up when they are done
for i := 0; i < numCPU; i++ {
endc <- nil
}
// sum results
sum := 0
for i := 0; i < numCPU; i++ {
procSum := <-sumc
sum += procSum
}
fmt.Println(sum)
}
func sumf(sumc, valuec chan int, endc chan interface{}) {
sum := 0
for {
select {
case i := <-valuec:
sum += i
case <-endc:
sumc <- sum
return
}
}
}
希望这会有所帮助。