“不要通过共享内存来通信,要通过通信来共享内存”,这句话是GO社区中非常经典的一句话,但是我们如何理解这句话呢?
GO语言的协程(goroutine)是从进程、线程基础上发展而来的,它比进程线程更轻量级,但是都是为并发而生。既然是并发,那么不可避免的会有多个不同并发实体之间传播或者交换信息,也即通信。要理解“不要通过共享内存来通信,要通过通信来共享内存”这句话,我们得从跟进程线程间通信的比较来了解。
因为GO的协程间的通信都是在同一个进程内进行,所以没有必要跟进程间通信做比较,只需要跟线程间通信做比较即可。

线程间通信

两个或者多个线程间要传播或者交换信息,通常的做法有:

  • 分配一个共享的变量,多个线程获取或者修改这个变量来交换信息。变量本质上就是一片共享的内存。
  • 通过队列来实现消费者和生产者的模式来进行通信。那么队列本质上也是线程间共享同一块内存。当然也可以把队列理解为一个共享的变量。
  • 线程同步机制来控制线程之间的运行,比如同步锁、信号量、条件变量。共享变量以及队列也都需要用到线程同步机制来保证数据和通信的正确性。

一般线程同步在线程间交换的信息仅仅是控制信息,比如某个A线程释放了锁,B线程能获取到锁并开始运行,这个不涉及数据的交换。数据的交换主要还是通过共享内存(共享变量或者队列)来实现,为了保证数据的安全和正确性,共享内存就必需要加锁等线程同步机制。而线程同步使用起来特别麻烦,容易造成死锁,且过多的锁会造成线程的阻塞以及这个过程中上下文切换带来的额外开销。

GO中通过channel来共享内存

GO语言中,要传递某个数据给另一个goroutine(协程),可以把这个数据封装成一个对象,然后把这个对象的指针传入某个channel中,另外一个goroutine从这个channel中读出这个指针,并处理其指向的内存对象。GO从语言层面保证同一个时间只有一个goroutine能够访问channel里面的数据,为开发者提供了一种优雅简单的工具,所以GO的做法就是使用channel来通信,通过通信来传递内存数据,使得内存数据在不同的goroutine中传递,而不是使用共享内存来通信。
————————————————

原文链接:https://blog.csdn.net/c359719435/article/details/78785189