Use golang concurrency summation as an exercise for golang concurrency.
In order to verify the correctness of the results, the most traditional version should be given:
func sum1(data []int) int { s := 0 l := len(data) for i := 0; i < l; i++ { s += data[i] } return s }
The second method
Use N goroutines, and then write the N segmented sums into N channels:
func sum2(data []int) int { s := 0 l := len(data) const N = 5 seg := l / N var chs [N]<-chan int for i := 0; i < N; i++ { chs[i] = worker(data[i*seg : (i+1)*seg]) } for i := 0; i < N; i++ { s += <-chs[i] } return s } func worker(s []int) <-chan int { out := make(chan int) go func() { length := len(s) sum := 0 for i := 0; i < length; i++ { sum += s[i] } out <- sum }() return out }
For a summing task, using the "mode" like worker may be too troublesome.
Look at the third type
Write it directly with a function:
func sum3(data []int) int { s := 0 l := len(data) const N = 5 seg := l / N var mu var wg (N) // Add N directly for i := 0; i < N; i++ { go func(ii int) { tmpS := data[ii*seg : (ii+1)*seg] ll := len(tmpS) () for i := 0; i < ll; i++ { s += tmpS[i] } () () // A goroutine is finished running }(i) } () // Wait until N goroutines are running return s }
Note that sum3 must be locked at the place where s is read and written, because s may be read and written concurrently by multiple goroutines.
The last method has the data race problem
However, the operation result is correct, let’s take a look at the idea:
var sum4Tmp int var sum4mu // This has a data race problem, and you can use WaitGroup to modify it, just to provide a way of thinkingfunc sum4(data []int) int { //s := 0 l := len(data) const N = 5 seg := l / N for i := 0; i < N; i++ { go subsum4(data[i*seg : (i+1)*seg]) } // Here is >1, because main is to be excluded // This method is unreliable, just a way of thinking for () > 1 { } // go run -race will report data race problems // main goroutine reads it // Other goroutines will write to it (go subsum4) return sum4Tmp } func subsum4(s []int) { length := len(s) sum := 0 () for i := 0; i < length; i++ { sum += s[i] } sum4Tmp = sum4Tmp + sum defer () }
The final test is as follows:
First create a slice, put 1e8 (100 million) integers (range [0,10)) into it,
Then use 4 methods to calculate
func calcTime(f func([]int) int, arr []int, tag string) { t1 := ().UnixNano() s := f(arr) t2 := ().UnixNano() - t1 ("%15s: time: %d, sum: %d\n", tag, t2, s) } func main() { const MAX = 1e8 // 100 million arr := make([]int, MAX) for i := 0; i < MAX; i++ { arr[i] = (10) } calcTime(sum1, arr, "for") calcTime(sum2, arr, "worker") calcTime(sum3, arr, "WaitGroup") calcTime(sum4, arr, "NumGoroutine") }
My laptop output result:
for: time: 61834200, sum: 450032946
worker: time: 51861100, sum: 450032946
WaitGroup: time: 153628200, sum: 450032946
NumGoroutine: time: 63791300, sum: 450032946
Welcome to add corrections!
Supplement: Golang concurrent summation (competition rather than segmentation)
Give an example
How to solve the problem of requiring 2 goroutines to complete sums of 1 to 100 instead of segmentation?
Solution:
var wg var ch chan int32 var receiveCh chan int32 func add(){ var sum int32 sum = 0 Loop: for { select { case val, ok := <-ch: if ok { atomic.AddInt32(&sum, val) } else { break Loop } } } receiveCh <- sum () } func main() { (3) ch = make(chan int32) receiveCh = make(chan int32, 2) go func(){ for i := 1; i <= 100; i++{ n := i //Avoid data competition ch <- int32(n) } close(ch) () }() go add() go add() () close(receiveCh) var sum int32 sum = 0 for res := range receiveCh{ sum += res } ("sum:",sum) }
The above is personal experience. I hope you can give you a reference and I hope you can support me more. If there are any mistakes or no complete considerations, I would like to give you advice.