《Go 语言并发之道》读书笔记(一)

已经把《Go 语言并发之道》通读了一遍,非常不错的一本书,对于理解掌握Go语言的并发知识有很大的帮助,接下来我会把书中有用的知识通过代码示例出来,把一些比较好的知识点记录下来。
首先我们来看一段代码

var data int
go func() { data++ }()
if data == 0 {
	fmt.Println(" the value is 0.")
} else {
	fmt.Printf(" the value is %v.\n", data)
}

这段代码我们想把data + 1 后打印出来,但是结果打印出来的效果是 “the value is 0.”, 没有达到我们的预期,主要是因为调用 data++ 的这个goroutine没有先执行。 并发的难点就是控制程序执行的先后顺序。 那么我们能不能这样改进一下呢? 加一个sleep让主goroutine等待一下。

var data int
go func() { data++ }()
time.Sleep(1 * time.Second)
if data == 0 {
	fmt.Println(" the value is 0.")
} else {
	fmt.Printf(" the value is %v.\n", data)
}

打印出来的结果是 “the value is 1.”, 似乎达到了我们的预期, 但是实际是是不行的,也许data++方法里面还有耗时的操作,那程序运行的结果又有不确定性了。
这个程序还有个很大的问题, 两个goroutine共享了内存data, 如果这个data是只读的那还好,不会有什么影响,但是如果它是需要改变的,那么两个goroutine拿到的数据会存在不确定性。那么是否能够通过加锁来解决这个问题呢? 如下示例代码

	var memoryAccess sync.Mutex

	var data int
	go func() {
		memoryAccess.Lock()
		data++
		memoryAccess.Unlock()
	}()

	memoryAccess.Lock()

	if data == 0 {
		fmt.Println(" the value is 0.")
	} else {
		fmt.Printf(" the value is %v.\n", data)
	}
	memoryAccess.Unlock()

通过加锁我们能保证访问data的时候是独占的,但是它依然解决不了代码执行先后问题,而且看上去很不优雅。 既优雅又能解决问题的方法是下面的代码

	c := make(chan int)
	var data int

	go func() {
		data++
		c <- data
	}()

	data = <-c
	if data == 0 {
		fmt.Println(" the value is 0.")
	} else {
		fmt.Printf(" the value is %v.\n", data)
	}

输出结果“the value is 1.”
上面的代码定义了一个channel, 通过channel来传递value, 主goroutine遇到读取channel( <-c)的地方会等待,等待副goroutine把值填进去(c <- data), 其它部分的代码并发执行。
这里贴出书上Go语言并发性哲学总结: 追求简洁, 尽量使用channel, 并且认为goroutine的使用是没有成本的。
Go语言的座右铭: 使用通信来共享内存,而不是通过共享内存来通信

总结

这个例子虽然很简单,但是它能够引导我们进入Go语言并发的世界,让我们明白如何通过goroutine和channel来优雅的写出并发代码。 后续我们将列举出更多的示例,通过示例来说明一下知识。

posted @   dk168  阅读(114)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示