GO语言并发编程入门:使用管道求单个/多个数组和
求数组和
需求:定义函数,求一个整数类型切片中所有元素的和。
示例代码:
package main
import "fmt"
// 求和函数
func getArrSum(arr []int){
sum := 0
for _,v:= range arr {
sum+=v
}
fmt.Println(sum)
}
func main() {
// 构建数组
arr := []int{1, 2}
// 求和
getArrSum(arr)
}
使用管道求单个数组和
需求:在上个案例的基础上,使用管道存储求和结果。定义一个管道作为函数的参数,在函数中求和结束后将求和结果写入到管道,在主协程中,读取管道中的结果并打印。
示例代码:
package main
import "fmt"
// 求和函数
func getArrSum(arr []int, c chan<- int){
sum := 0
for _,v:= range arr {
sum+=v
}
c<- sum // 将求和结果写入管道
}
func main() {
// 构建数组
arr := []int{1, 2}
// 构建管道
c := make(chan int)
// 开启一个协程进行求和
go getArrSum(arr, c)
// 等待计算结束后读取求和结果
sum := <-c
// 查看结果
fmt.Println(sum)
}
通过本案例我们应该掌握:
- 普通管道的定义方式:chan 类型
- 只写管道的定义方式:chan<- 类型
- 只读管道的定义方式:<-chan 类型
使用管道求多个数组和
需求:在之前案例的基础上,实现同时求多个数组的和。比如,求[1,2], [3,4], [5,6]三个数组的和。
示例代码:
package main
import "fmt"
// 求和函数
func getArrSum(arr []int, c chan<- int){
sum := 0
for _,v:= range arr {
sum+=v
}
c<- sum // 将求和结果写入管道
}
func main() {
// 构建数组
arr1 := []int{1, 2}
arr2 := []int{3, 4}
arr3 := []int{5, 6}
// 构建管道
c := make(chan int)
// 开启一个协程进行求和
go getArrSum(arr1, c)
go getArrSum(arr2, c)
go getArrSum(arr3, c)
// 等待计算结束后读取求和结果
// 管道写了三次,就要读取三次
// 这里有一个非常重要的特性,管道是一种类似栈结构,先进后出
// 所以,我们传入的是arr1、arr2、arr3,得到的却是sum3、sum2、sum1
sum3 := <-c
sum2 := <-c
sum1 := <-c
// 查看结果
fmt.Println(sum1, sum2, sum3)
}
案例分析:通过本案例我们应该掌握
- 管道是一种栈结构,先进后出
- 往管道里面写了多少个数据,就必须要读多少次,否则可能会造成死锁
将单数组拆分多数组并发求和
需求:在之前案例的基础上,我们将一个数组,拆分为多个数组进行并发求和。比如将[12,3,4,5,6],拆分为[1,2], [3,4], [5,6]进行并发求和。
示例代码:
package main
import "fmt"
// 求和函数
func getArrSum(arr []int, c chan<- int){
sum := 0
for _,v:= range arr {
sum+=v
}
c<- sum // 将求和结果写入管道
}
func main() {
// 构建数组
arr := []int{1,2,3,4,5,6}
fmt.Println(arr[:2])
fmt.Println(arr[2:4])
fmt.Println(arr[4:])
// 构建管道
c := make(chan int)
// 开启一个协程进行求和
go getArrSum(arr[:2], c)
go getArrSum(arr[2:4], c)
go getArrSum(arr[4:], c)
// 等待计算结束后读取求和结果
// 管道写了三次,就要读取三次
// 这里有一个非常重要的特性,管道是一种类似栈结构,先进后出
// 所以,我们传入的是arr1、arr2、arr3,得到的却是sum3、sum2、sum1
sum3 := <-c
sum2 := <-c
sum1 := <-c
// 查看结果
fmt.Println(sum1, sum2, sum3)
}
案例分析:通过本案例我们应该掌握
- Go语言中的数组也叫切片或slice,和Python里面的列表类似,是可以通过切片表达式进行局部访问的
- 利用切片的特性,我们可以非常轻松的实现将一个大数组拆分为多个小数组,进行并发求和
非并发求数组和
需求:构造一个具有100万个随机10-110范围内的整数的切片,并编写一个求和函数,求切片中所有元素的和,并计算求和需要的时间。
如何生成随机浮点数
package main
import (
"fmt"
"math/rand"
"time"
)
func init() {
rand.Seed(time.Now().UnixNano())
}
func main() {
for i := 0; i < 10; i++ {
fmt.Println(rand.Float64())
}
}
如何生成指定范围随机整数
package main
import (
"fmt"
"math"
"math/rand"
"time"
)
func init() {
rand.Seed(time.Now().UnixNano())
}
func main() {
start := 10
end := 110
for i := 0; i < 10; i++ {
num := rand.Float64()*float64(end) + float64(start)
numInt := int(math.Floor(num))
fmt.Println(numInt)
}
}
如何生成整数切片数组
package main
import (
"fmt"
"math"
"math/rand"
"time"
)
func init() {
rand.Seed(time.Now().UnixNano())
}
func getArr(min, max, length int) (arr []int) {
for i := 0; i < length; i++ {
num := rand.Float64()*float64(max) + float64(min)
numInt := int(math.Floor(num))
arr = append(arr, numInt)
}
return
}
func main() {
start := 10
end := 110
length := 1000000
arr := getArr(start, end, length)
fmt.Println(arr[:3], len(arr))
}
如何求切片数组和
package main
import (
"fmt"
"math"
"math/rand"
"time"
)
func init() {
rand.Seed(time.Now().UnixNano())
}
func getArr(min, max, length int) (arr []int) {
for i := 0; i < length; i++ {
num := rand.Float64()*float64(max) + float64(min)
numInt := int(math.Floor(num))
arr = append(arr, numInt)
}
return
}
func getArrSum(arr []int) (sum int) {
for _, num := range arr {
sum += num
}
return
}
func main() {
start := 10
end := 110
length := 1000000
arr := getArr(start, end, length)
sum := getArrSum(arr)
fmt.Println(sum)
}
如何计算求和时间
package main
import (
"fmt"
"math"
"math/rand"
"time"
)
func init() {
rand.Seed(time.Now().UnixNano())
}
func getArr(min, max, length int) (arr []int) {
for i := 0; i < length; i++ {
num := rand.Float64()*float64(max) + float64(min)
numInt := int(math.Floor(num))
arr = append(arr, numInt)
}
return
}
func getArrSum(arr []int) (sum int) {
for _, num := range arr {
sum += num
}
return
}
func main() {
start := 10
end := 110
length := 1000000
arr := getArr(start, end, length)
startTime := time.Now()
sum := getArrSum(arr)
fmt.Println(sum)
spendTime := time.Since(startTime)
fmt.Println(spendTime)
}
并发求数组和
需求:
- 定义一个方法,接受一个数组和一个管道,对数组求和并将结果写入管道
- 定义一个方法,接受一个数组,如果数组元素个数大于3个,则将数组等分为3个子数组,并发求和
- 生成100万个随机10-110之间整数构成的随机数组,并发求和并计算时间
如何将求和结果写入管道
package main
import (
"fmt"
"math"
"math/rand"
"time"
)
func init() {
rand.Seed(time.Now().UnixNano())
}
func getArr(min, max, length int) (arr []int) {
for i := 0; i < length; i++ {
num := rand.Float64()*float64(max) + float64(min)
numInt := int(math.Floor(num))
arr = append(arr, numInt)
}
return
}
func getArrSum(arr []int) (sum int) {
for _, num := range arr {
sum += num
}
return
}
func writeArrSumChan(arr []int, c chan<- int) {
c <- getArrSum(arr)
}
func main() {
start := 10
end := 110
length := 1000000
arr := getArr(start, end, length)
startTime := time.Now()
c := make(chan int)
go writeArrSumChan(arr, c)
sum := <-c
fmt.Println(sum)
spendTime := time.Since(startTime)
fmt.Println(spendTime)
// 主动等待结束
time.Sleep(time.Second * 3)
}
如何并发求和
package main
import (
"fmt"
"math"
"math/rand"
"time"
)
func init() {
rand.Seed(time.Now().UnixNano())
}
func getArr(min, max, length int) (arr []int) {
for i := 0; i < length; i++ {
num := rand.Float64()*float64(max) + float64(min)
numInt := int(math.Floor(num))
arr = append(arr, numInt)
}
return
}
func getArrSum(arr []int) (sum int) {
for _, num := range arr {
sum += num
}
return
}
func writeArrSumChan(arr []int, c chan<- int) {
c <- getArrSum(arr)
}
// 并发求和
func getArrSum2(arr []int) (sum int) {
// 不需要并发求和
length := len(arr)
if length <= 3 {
sum = getArrSum(arr)
}
// 拆分数组
step := length / 3
arr1 := arr[:step]
arr2 := arr[step : step+step]
arr3 := arr[step+step:]
// 并发求和
c := make(chan int)
go writeArrSumChan(arr1, c)
go writeArrSumChan(arr2, c)
go writeArrSumChan(arr3, c)
v1, v2, v3 := <-c, <-c, <-c
sum += v1 + v2 + v3
return
}
func main() {
var (
start = 10
end = 110
length = 100000000
arr = getArr(start, end, length)
startTime time.Time
spendTime time.Duration
sum int
)
// 并发求和
startTime = time.Now()
sum = getArrSum2(arr)
fmt.Println(sum)
spendTime = time.Since(startTime)
fmt.Println("并发求和消耗时间:", spendTime)
// 非并发求和
startTime = time.Now()
sum = getArrSum(arr)
fmt.Println(sum)
spendTime = time.Since(startTime)
fmt.Println("非并发求和消耗时间:", spendTime)
// 主动等待结束
time.Sleep(time.Second * 3)
}
输出结果:
6450261436 并发求和消耗时间: 25.405516ms 6450261436 非并发求和消耗时间: 47.803627ms
THE END






