如何在并行for循环中使用通道

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
}

I'm trying to learn the parallel ability to speed up things like OpenMP. And here is an example of the intended summing up parallel loop in Go, this function runs as a goroutine.

Note that the variable sum is not a channel here, so does this mean the variable sum access inside the for loop is a blocked operation? Is it now efficient enough? Is there a better solution?

I knew the channel feature was designed for this, my obviously wrong implement below can compile, but with 100 runtime errors like following.

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

So what's the problem here? it seems summing is not a good example for paralleled for-loop, but actually I wish to know how to use channel inside paralleled for-loop.

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
}

both with the same main function

func main(){
    pc := make(chan int)
    go parallelSum(pc) 
    result = <- pc
    fmt.Println("parallel result:", result)
}

I don't like the idea of summing numbers through channels. I'd rather use something classical like sync.Mutex or atomic.AddUint64. But, at least, I made your code working. We aren't able to pass a value from one channel to another (I added temp variable). Also, there is sync.WaitGroup and other stuff. But I still don't like the idea of the code.

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
}

When using go routines (i.e. go foo()), it is preferable to use communication over memory-sharing. In this matter, as you mention, channels are the golang way to handle communication.

For your specific application, the paralleled sum similar to OpenMP, it would be preferable to detect the number of CPUs and generate as many routines as wished:

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
        }
    }
}

Hopefully, this helps.