这个实例通过循环实现并行的分段求和计算,再把各个子段和加到总和中。
通过这个实例可以了解如何实现循环并行处理,以及有关的编程技巧。
但是这个程序是有问题的,因为可能发生变量访问冲突问题,导致计算结果不正确。这个程序是不稳定的,有时能够计算出不正确的结果,有时能够计算出正确结果。
程序中的变量sum是共享变量,需要使用同步用的互斥锁来保证计算的正确性。正解程序附在本博文的最后。
Go语言程序(不稳定,会出错):
// loopgoroutine project main.go
package main
import (
"fmt"
"runtime"
"time"
)
const START = 1
const LEN = 100
const STEP = 1000
var sum int64
func main() {
fmt.Printf("%d\n", (int64(LEN*STEP) * (int64(LEN*STEP) + 1) / int64(2)))
sum = 0
start := START
for i := 1; i <= STEP; i++ {
go subsum(start, LEN)
start += LEN
}
for runtime.NumGoroutine() > 1 {
time.Sleep(100 * time.Millisecond)
}
fmt.Printf("%d\n", sum)
}
func subsum(start int, len int) {
var ssum int64
ssum = 0
for i := 1; i <= len; i++ {
ssum += int64(start)
start++
}
sum += ssum
}
运行结果(可能是以下两种,也可能算出其他的结果):
5000050000
5000050000
5000050000
4713772650
程序说明:
1.这个程序总的功能是计算1到100000(LEN×STEP)的和,计算被分为STEP步(段)进行,通过调用函数subsum()计算每段之和,然后相加
2.函数subsum()计算从start开始长度为len的数列之和
3.语句"fmt.Printf("%d\n", (int64(LEN*STEP) * (int64(LEN*STEP) + 1) / int64(2)))"打印输出一个正确的结果作为参考值
4.为了知道程序当前有几个goroutine在运行,需要使用包"runtime",其中的方法runtime.NumGoroutine()返回正在运行的goroutine的数量,需要注意的是main()本身也是一个goroutine
5.使用包"time"中的方法time.Sleep(),让自身的goroutine休眠,代入参数指定休眠0.1秒,因为需要等待所有其他goroutine都执行完之后程序才能结束
6.使用互斥锁mu来锁住变量sum(参见程序),需要使用包"sync"
Go语言程序(正解):
// loopmutex project main.go
package main
import (
"fmt"
"runtime"
"sync"
"time"
)
const START = 1
const LEN = 100
const STEP = 1000
var (
mu sync.Mutex
sum int64
)
func main() {
fmt.Printf("%d\n", (int64(LEN*STEP) * (int64(LEN*STEP) + 1) / int64(2)))
sum = 0
start := START
for i := 1; i <= STEP; i++ {
go subsum(start, LEN)
start += LEN
}
for runtime.NumGoroutine() > 1 {
time.Sleep(100 * time.Millisecond)
}
fmt.Printf("%d\n", sum)
}
func subsum(start int, len int) {
var ssum int64
ssum = 0
for i := 1; i <= len; i++ {
ssum += int64(start)
start++
}
mu.Lock()
sum += ssum
mu.Unlock()
}