版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013862108/article/details/88623218
约束: 在编写并发代码的时候,有以下几种不同的保证操作安全的方法。 1。 用于共享内存的同步原语(如sync.Mutex) 2. 通过通信来 共享内存来进行同步(如 channel) 在并发处理中还有其他几种情况也是隐式并发安全的: 3。 不会发生改变的数据 4。 受到保护的数据 约束: 特定约束,和 词法约束 特定约束:是通过公约实现约束的。 无论是由语言社区, 你所在的团队, 还是你的代码库设置。 在我看来,坚持约束很难在任何规模 的项目上 进行协调。 除非你有工具在每次有人提交代码时对你的代码进行静态分析。
func main() {
data := make([]int, 4) //创建一个 数组
loopData := func(handleData chan<- int) {
defer close(handleData)
for i := range data{
handleData <- data[i]
}
}
handleData := make(chan int)
go loopData(handleData)
for num := range handleData{
fmt.Println(num)
}
}
//0
//0
//0
//0
按照惯例: 我们只能从 loopData函数访问它。 不能直接 range data
词法约束: 使用词法作用域 公开 用于多个并发进程的正确数据。 这使得做错事是不可能的。回想一下 channel 部分,它讨论的是将channel 的读写处理 暴露给需要它们的并发进程。
func main(){
chanOwner := func() <-chan int{
//在chanOwner 函数的词法范围内实例化channel.这将结果写入channel 的处理的范围约束在它下面定义的闭包中。
results := make(chan int, 5)
go func() {
defer close(results)
for i:=0 ;i<5; i++{
results <- i
}
}()
return results
}
//将channel 的使用约束为只读。
consumer := func(results <-chan int) {
for result := range results{
fmt.Printf("Received: %d\n", result)
}
fmt.Println("Done receiving!")
}
results := chanOwner()
consumer(results)
}
channel 是并发安全的, 来看一个使用 不是并发安全的数据结构的约束例子,它是 bytes.Buffer
func main(){
printData := func(wg *sync.WaitGroup, data []byte){
defer wg.Done()
var buff bytes.Buffer
for _, b := range data{
fmt.Fprintf(&buff, "%c", b)
}
fmt.Println(buff.String())
}
var wg sync.WaitGroup
wg.Add(2)
data := []byte("golang")
go printData(&wg, data[:3])
go printData(&wg, data[3:])
wg.Wait()
}
//ang
//gol
我们传入切片的不同子集,因此约束了我们开始的goroutine。 由于词法范围的原因,我们已经不可能执行错误的操作,所以我们不需要通过通信完成
内存访问同步 或 共享数据。
我们传入切片的不同子集,因此约束了我们开始的goroutine。 由于词法范围的原因,我们已经不可能执行错误的操作,所以我们不需要通过通信完成内存访问同步 或 共享数据。