一、为什么需要channel
1、需求:
现在要计算 1-200 的各个数的阶乘,并且把各个数的阶乘放入到map中。最后显示出来。要求使用goroutine完成
1)、分析思路:
使用goroutine 来完成,效率高,但是会出现并发/并行安全问题.
这里就提出了不同goroutine如何通信的问题
2)、代码实现
使用goroutine来完成(看看使用gorotine并发完成会出现什么问题? 然后我们会去解决)
在运行某个程序时,如何知道是否存在资源竞争问题。 方法很简单,在编译该程序时,增加一个参数 -race
即可
3)、示意图
4)、代码实现:
package utils
import (
"sync"
"fmt"
"time"
)
// 需求:现在要计算 1-200 的各个数的阶乘,并且把各个数的阶乘放入到map中。
// 最后显示出来。要求使用goroutine完成
// 思路
// 1. 编写一个函数,来计算各个数的阶乘,并放入到 map中.
// 2. 我们启动的协程多个,统计的将结果放入到 map中
// 3. map 应该做出一个全局的.
var (
myMap = make(map[int]int, 10)
)
// cacluFactorial 函数就是计算 n!, 让将这个结果放入到 myMap
func cacluFactorial(n int) {
res := 1
for i := 1; i <= n; i++ {
res *= i
}
//这里我们将 res 放入到myMap
myMap[n] = res //concurrent map writes?
}
func FactorialDemo() {
// 我们这里开启多个协程完成这个任务[200个]
for i := 1; i <= 200; i++ {
go cacluFactorial(i)
}
//休眠10秒钟【第二个问题 】
time.Sleep(time.Second * 10)
//这里我们输出结果,变量这个结果
for i, v := range myMap {
fmt.Printf("map[%d]=%d\n", i, v)
}
}
2、不同goroutine之间如何通讯
- 全局变量的互斥锁
- 使用管道channel来解决
3、使用全局变量加锁同步改进程序
因为没有对全局变量 m 加锁,因此会出现资源争夺问题,代码会出现错误,提示concurrent map writes
解决方案:加入互斥锁
我们的数的阶乘很大,结果会越界,可以将求阶乘改成 sum += uint64(i)
代码改进
package utils
import (
"sync"
"fmt"
"time"
)
// 需求:现在要计算 1-200 的各个数的阶乘,并且把各个数的阶乘放入到map中。
// 最后显示出来。要求使用goroutine完成
// 思路
// 1. 编写一个函数,来计算各个数的阶乘,并放入到 map中.
// 2. 我们启动的协程多个,统计的将结果放入到 map中
// 3. map 应该做出一个全局的.
var (
myMap = make(map[int]int, 10)
/*同步锁改进代码*/
//声明一个全局互斥锁
lock sync.Mutex //sync包提供了基本的同步基元,如互斥锁。Mutex是一个互斥锁