当程序中使用goroutine来操作一个全局变量时,拿map来举例,同时使用多个协程来向map中写入数据,此时代码可能会报错.
package main
import (
"fmt"
)
var (
result = make(map[int]int, 10)
)
func Strata(num int) {
res := 1
for i := 1; i <= num ; i ++ {
res *= i
}
// 将结果放入map中
result[num] = res
}
// 使用全局变量加锁方式 解决了 并发写入问题,但是 不知道具体 协程什么时候运行结束
// 那么这个问题怎么解决呢?
func main() {
// 这里开启多个协程, 完成这个任务
// 问题1: fatal error: concurrent map writes (存在并发安全问题)
// 问题2: 通过 go build -race main.go >> 拿到main.exe,并运行 >> Found 2 data race(s) 发现有两个存在竞争关系
for i := 1; i <= 20 ; i ++ {
go Strata(i)
}
// 输出结果
for i, v := range result {
fmt.Printf("result[%v]=%v
", i, v)
}
}
fatal error: concurrent map writes
上面信息表示,当前map存在并发安全问题。
通过上面代码引出,有两种解决办法,一是使用golang提供的 sync包中的Mutex互斥锁来解决,在添加前后加锁。
另一种办法则是使用channel(管道)。channel是线程安全,多个协程操作同一管道时,不会发生资源竞争问题。 建议:使用channel时最好使用存放同一种数据类型。
package main
import (
"fmt"
)
type Stu struct {
Name string
Age int
}
func main() {
// 定义一个管道
var newChan chan interface{}
newChan = make(chan interface{}, 10)
newChan <- "Mic"
newChan <- 10
// 添加一个Cat结构体
stu := Stu{"Tom", 20}
// 添加一个元素到newChan的channel中
newChan <- stu
// 如果想要取得最后一个元素,则先把前面的元素移除
<- newChan
<- newChan
newStu := <- newChan
// 打印newStu类型以及值
// 打印结果newStu=main.Stu, newStu={Tom 20}
fmt.Printf("newStu=%T, newStu=%v
", newStu, newStu)
// 打印newStu的值
// 这样取直接报错: newStu.Name undefined (type interface{} has no field or method Name)
// 因为取出的是一个空接口, 表示没有Name这个属性。
//fmt.Println("newStu.Name=", newStu.Name)
// 解决上面的问题,需要使用到前面的说过的 类型断言
c := newStu.(Stu)
fmt.Println("c.Name=", c.Name) // 这样一来就不会报错了。
}
newStu=main.Stu, newStu={Tom 20}
c.Name= Tom
熟悉了Channel的基本使用, 则在使用协程操作时, 只需定义一个全局的管道,则就可以继续操作。
其他操作,后续继续学习。
留言与评论(共有 0 条评论) “” |