对于协程的调度,我们确实必须保存它的上下文,因为这是每个正常中断再运行的函数所必须的;但这种操作,在go语言中,全权交给了语言本身;至于内存的组织,应当是保存在所属进程的栈中。
CSP并发模型
Golang 语言中实现了两种并发模式,一种是我们熟悉的线程与锁并发模型,它主要依赖于共享内存实现。线程与锁模型类似于对底层硬件运行过程的形式化,程序的正确运行很大程度依赖于开发人员的能力和技巧,程序在出错时不易排查。另一种是 Golang 中倡导使用的 CSP(communicating sequential processes)通信顺序进程模型。
它倡导使用通信的手段来共享内存。CSP 模型中存在两个关键的概念:
- 并发实体,通常可以理解为执行线程,它们相互独立,且并发执行;
- 通道,并发实体之间使用通道发送信息。
与共享内存的线程与锁并发模型不同,CSP 中的并发实体是独立的,它们之间没有共享的内存空间。并发实体之间的数据交换通过通道实现,无论在通道中放数据还是从通道中取数据,都会导致并发实体的阻塞,直到通道中的数据被取出或者通道中被放入新的数据,并发实体通过这种方式实现同步。
CSP 类似于我们常用的同步队列,它关注的是消息传输的方式,即通道,消息的具体发送实体和具体接收实体并不关注。发送和接收信息的并发实体可能不知道对方具体是谁,它们之间是互相解耦的。通道与并发实体也不是紧耦合的,通道可以独立地进行创建和放取,并在不同的并发实体中传递使用。
CSP 通道的特性给并发编程提供了极大的灵活性,通道作为独立的对象,可以被任意创建、读取、放入数据,并在不同的并发实体中被使用。但是它也极易导致死锁,如果一个并发实体在读取一个永远没有数据放入的通道或者把数据放入一个永远不会被读取的通道中,那么它将被永远阻塞。