需求
计算 1 - 200 各个数的阶乘,然后存放到map中, 并输出
代码
// channel 引出package mainimport ("fmt""time")// 计算 1 - 200 各个数的阶乘,然后存放到map中, 并输出// 思路// 1、编写一个函数 计算各个数的阶层,并放入到 map 中// 2、启动多个协程,将统计结果放入 map 中// 3、map 应该是全局的var (myMap = make(map[int]int, 10))// 编写计算阶乘的函数,并将结果放入 mapfunc test(n int) {res := 1for i := 1; i <= n; i++ {res *= i}// 放入 mapmyMap[n] = res}func main() {for i := 0; i < 200; i++ {go test(i)}// 在这里 休眠 10s 中 ?, 尝试等待协程运行结束time.Sleep(10 * time.Second)// 遍历输出结果 主线程瞬间结束,程序退出,无输出for i, v := range myMap {fmt.Printf("myMap[%v]=%v \n", i, v)}}
问题

fatal error: concurrent map writes
Map,对于共享变量,资源,并发写会产生竞争, 共享资源遭到破坏,
命令查看资源是否存在竞争 -race
go build -race main.go // 得到 main.exemain.exe // 运行 main.exe// 输出:...myMap[161]=0myMap[170]=0myMap[191]=0myMap[193]=0myMap[195]=0myMap[149]=0myMap[154]=0myMap[86]=0myMap[104]=0myMap[110]=0myMap[124]=0myMap[178]=0myMap[180]=0myMap[19]=121645100408832000myMap[82]=0myMap[187]=0myMap[194]=0myMap[152]=0myMap[153]=0myMap[51]=-162551799050403840myMap[53]=-5270900413883744256myMap[106]=0myMap[176]=0myMap[181]=0myMap[22]=-1250660718674968576myMap[32]=-6045878379276664832Found 2 data race(s) // 有两个资源存在竞争
不同goroutine之间如何通讯
使用全局变量加锁,同步改进程序
因为没有对全局变量 m 加锁,因此会出现资源争夺问题,代码会出现错误提示: concurrent map writes
解决方案:加入互斥锁
map 加锁,没有关闭则排队等待
协程goroutine
持有锁——lock
|
map空间
|
释放锁——unlock
队列——排队等待
import “sync”
sync包提供了基本的同步基元,如互斥锁。除了Once和WaitGroup类型,大部分都是适用于低水平程序线程,高水平的同步使用channel通信更好一些。
代码
// channel 引出package mainimport ("fmt""sync""time")// 计算 1 - 200 各个数的阶乘,然后存放到map中, 并输出// 思路// 1、编写一个函数 计算各个数的阶层,并放入到 map 中// 2、启动多个协程,将统计结果放入 map 中// 3、map 应该是全局的var (myMap = make(map[int]int, 10)// 声明一个全局互斥锁lock sync.Mutex)// 编写计算阶乘的函数,并将结果放入 mapfunc test(n int) {res := 1for i := 1; i <= n; i++ {res *= i}// 操作 map 前加锁lock.Lock()// 放入 mapmyMap[n] = res// 操作完之后解锁lock.Unlock()}func main() {for i := 0; i < 20; i++ {go test(i)}// 休眠 10s 中 ?time.Sleep(10 * time.Second)// 遍历输出结果 主线程瞬间结束,程序退出,无输出lock.Lock()for i, v := range myMap {fmt.Printf("myMap[%v]=%v \n", i, v)}lock.Unlock()}
问题
- 上面的主线程 休眠 10 秒,去等待协程执行完毕。如果时间设置的长了,协程已经执行完毕,就会造成资源的浪费;如果时间设置的短了,协程不执行完毕主线程就退出了。不够完美,需要进一步改进。
- 全局变量加锁同步来实现通讯,不利于多个协程对全局变量的读写操作
引出新的通讯机制: channel
