这个实例通过循环实现并行的分段求和计算,再把各个子段和加到总和中。

通过这个实例可以了解如何实现循环并行处理,以及有关的编程技巧。

但是这个程序是有问题的,因为可能发生变量访问冲突问题,导致计算结果不正确。这个程序是不稳定的,有时能够计算出不正确的结果,有时能够计算出正确结果。

程序中的变量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()
}