Java语言里解决并发问题靠的是多线程,但线程是个重量级的对象,不能频繁创建,销毁,而且线程切换的成本也很高,为了解决这些问题,Java SDK提供了线程池。然而用好线程池并不容易,并且Java也提供了很多工具类。那有没有更好的解决方案呢?Java语言目前还没有,但是其他语言里有,这个方案就是协程。
协程可以理解为一种轻量级的线程。从操作系统的角度来看,线程是在内核态中调度的,而协程是在用户态调度的,所以相对线程来说,协程切换的成本更低。协程也有自己的栈,但是相比线程来说小得多,典型线程栈大小约为1M,而协程栈的大小往往只有几K或者几十K。
利用协程实现同步
Java里使用多线程并发地处理I/O,基本上用的都是异步非阻塞模型,这种模型的异步主要是靠注册回调函数实现的,能能否都使用同步处理呢?显然不能的。但是对于协程来说,等待的成本没有那么高,所以基于协程实现同步非阻塞是一个可行的方案。
Golang如何解决协作问题
Golang提供了两种不同的方案:
1,支持协程之间以共享内存的方式通信,Golang提供了管程和原子类对协程进行同步控制,这个方案于Java语言类似。
2,支持协程之间以消息传递的方式通信,本质是要避免共享,这个方案是基于CSP模型实现的。Golang比较推荐的方案是2。
CSP模型
CSP模型:Communicating Sequential Processes模型与Actor模型类似,彼此之间通信只能依靠消息传递的方式。不要以共享内存的方式通信,要以通信方式共享内存。
Golang中协程之间通信推荐的使用channel.
CSP模型与Actor模型区别
1,Actor模型中没有channel。虽然mailbox和channel非常像,但是区别还是很大的。mailbox对于程序员来说是透明的,并明确归属于一个特定的Actor,Actor之间可以直接通信,不需要通信中介。但是CSP模型中的channel,对于程序员来说是可见的,是通信的中介。
2,Actor模型中发送消息是非阻塞的,而CSP模型中是阻塞的。channel是一个阻塞队列,当阻塞队列已满的时候,向channel中发送数据,会导致发送消息的协程阻塞。
3,Actor模型理论上不保证消息百分之百送达,而在Golang实现的CSP模型中,是能够保证消息百分百送达的。
有疑问加站长微信联系(非本文作者)