我们知道,Java 语言的编码非常繁琐,为了应用设计模式而做了大量的冗长设计,而 Go 就不一样了。它提供了便利的并发编程方式,简简单单的 Go 语句,就可以创建多个 goroutine 执行并发任务。而且,Go 还提供了独特的 Channel 类型,很容易实现 goroutine 之间的数据交流。所以,Go 并发编程入门很容易,即使是初学者,要写一个使用 goroutine 异步输出“Hello World”的例子,也可以不费吹灰之力。
不过,和其他语言相比,Go 微服务治理框架的发展还是比较晚的。当阿里出品的 Java 微服务框架 Dubbo 被广泛应用时,Go 生态圈还没有微服务框架。
于是,四五年前,为了填补 Go 生态圈微服务化的缺失,一位大佬 Go 开发了一个微服务的框架 rpcx。它既有类似标准 rpc 库的易用特点,又包含了非常丰富的服务治理的功能。而且,根据benchmark 测试,rpcx 有着数一数二的性能,很多互联网企业(比如马蜂窝、百度等)都在使用。
结合我自己的开发经验,我真切地感受到了这一点:Go 并发编程的重要性不容置疑。只要是使用 Go 开发的大型应用程序,并发是必然要采用的技术。
但同时,我也了解到,很多人想要学习 Go 并发编程,却不知道该从何学起,也不知该如何精进。
学习 Go 并发编程,有哪些困难 ?
那学习 Go 并发会有哪些困难呢?我总结了一下,主要是有 5 大问题。
1、在面对并发难题时,感觉无从下手,不知道该用什么并发原语来解决问题。
2、如果多个并发原语都可以解决问题,那么,究竟哪个是最优解呢?比如说是用互斥锁,还是用 Channel。
3、不知道如何编排并发任务。并发编程不像是传统的串行编程,程序的运行存在着很大的不确定性。这个时候,就会面临一个问题,怎么才能让相应的任务按照你设想的流程运行呢?
4、有时候,按照正常理解的并发方式去实现的程序,结果莫名其妙就 panic 或者死锁了,排查起来非常困难。
5、已知的并发原语都不能解决并发问题,程序写起来异常复杂,而且代码混乱,容易出错。
每一位刚入门 Go 的程序员,在深入学习 Go 语言的时候,尤其是面对 Go 并发编程的时候,都会遇到这些问题。那么,具体该怎么学呢?
怎么提升 Go 并发编程能力?
学习这件事儿,最怕的就是不成体系,即使知识点之间是彼此独立的,也必定存在着联系。我们要做的,就是找出逻辑关系,拎出知识线。我认为,关于 Go 并发编程,有两条主线,分别是知识主线和学习主线。具体是啥意思呢?可以看下面的这张知识地图。
从图中可以看到,在知识主线层面,核心内容设计了 5 个模块:
基本并发原语:主要有 Mutex、RWMutex、Waitgroup、Cond、Pool、Context 等标准库中的并发原语,这些都是传统的并发原语,在其它语言中也很常见,是我们在并发编程中常用的类型。
**原子操作:**这部分,主要涉及Go 标准库中提供的原子操作。原子操作是其它并发原语的基础,学会了你就可以自己创造新的并发原语。
Channel:Channel 类型是 Go 语言独特的类型,因为比较新,所以难以掌握。全方位地学习 Channel 类型,你不仅能掌握它的基本用法,而且还能掌握它的处理场景和应用模式,避免踩坑。
扩展并发原语:目前来看,Go 开发组不准备在标准库中扩充并发原语了,但是还有一些并发原语应用广泛,比如信号量、SingleFlight、循环栅栏、ErrGroup 等。掌握了它们,就可以在处理一些并发问题时,取得事半功倍的效果。
分布式并发原语:分布式并发原语是应对大规模的应用程序中并发问题的并发类型。我主要会介绍使用 etcd 实现的一些分布式并发原语,比如 Leader 选举、分布式互斥锁、分布式读写锁、分布式队列等,在处理分布式场景的并发问题时,特别有用。
沿着这条知识主线,你建立起一个丰富的并发原语库。你可以把并发问题当成一个强大的敌人,而这些并发原语,就是我们的武器。每一种并发原语都有它的用处,你只有知道足够多的并发原语,才能灵活地应对各种场景。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
6120932195)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。