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