go并发: 并发时不用channel行不行?
一,并发时不使用channel,直接访问变量(共享内存)
代码:
// 入口函数
func main() {
//共享访问的切片
var ints []int
var wg sync.WaitGroup
//定义协程的数量
n:=10000
//定义wg的数量
wg.Add(n)
//创建指定数量的协程
for i := 0; i < n; i++ {
go func(i int) {
//fmt.Println("协程中写入:",i)
defer wg.Done()
ints = append(ints, i) // 多 goroutine 访问共享内存
}(i)
}
//等待结束
wg.Wait()
//打印数量
fmt.Println(len(ints))
}
运行效果:
$ go run main.go
9123
$ go run main.go
9835
$ go run main.go
10000
$ go run main.go
9976
$ go run main.go
9999
$ go run main.go
9979
虽然有可以正确写入的时候,但很多时候发生了没能成功写入的情况,
这就是并发访问共享内存,而没有相应的并发处理机制导致的后果
二,改进:用互斥锁 (Mutex) 保证对共享变量的安全访问
代码:
// 入口函数
func main() {
//共享访问的切片
var ints []int
var wg sync.WaitGroup
var mux sync.Mutex
//定义协程的数量
n:=10000
//定义wg的数量
wg.Add(n)
//创建指定数量的协程
for i := 0; i < n; i++ {
go func(i int) {
//fmt.Println("协程中写入:",i)
defer wg.Done()
mux.Lock() //加锁
ints = append(ints, i) // 多 goroutine 访问共享内存
mux.Unlock() //解锁
}(i)
}
//等待结束
wg.Wait()
//打印数量
fmt.Println(len(ints))
}
运行效果:
$ go run main.go
10000
$ go run main.go
10000
$ go run main.go
10000
$ go run main.go
10000
$ go run main.go
10000
$ go run main.go
10000
可见:在访问共享内存之前:先获取锁,
访问之后再解锁,这样不会再出现因并发导致的写入失败的情况
三,改进:并发写入时用channel实现,之后再从channel中读到到变量中
代码:
// 入口函数
func main() {
//共享访问的切片
var ints []int
//定义协程的数量
n:=10000
// 创建缓冲区为 n 的 Channel
channel := make(chan int, n)
//写入数据到channel
for i := 0; i < n; i++ {
go func(ch chan<- int, val int) {
ch <- val // 写入 Channel
}(channel, i)
}
//从channel中读取数据
for i := range channel {
ints = append(ints, i)
if len(ints) == n {
break
}
}
// 关闭 Channel
close(channel)
//打印数量
fmt.Println(len(ints))
}
运行效果:
$ go run main.go
10000
$ go run main.go
10000
$ go run main.go
10000
$ go run main.go
10000
$ go run main.go
10000
$ go run main.go
10000
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
2021-03-01 spring boot单元测试之二:用MockMvc为controller做单元测试(spring boot 2.4.3)
2020-03-01 docker的常用操作之二:docker内无法解析dns之firewalld设置等
2020-03-01 centos8安装fastdfs6.06集群方式三之:storage的安装/配置/运行
2020-03-01 centos8安装fastdfs6.06集群方式二之:tracker的安装/配置/运行
2020-03-01 centos8安装fastdfs6.06集群方式一之:软件下载与安装
2020-03-01 fastdfs之同一台storage server下包含多个store path
2020-03-01 centos8安装fastdfs6.06(单机方式)