1. Goroutine 是绿色线程,下面自带调度器。可以在 syscall 进入阻塞状态的时候自动出让 CPU(类似 Java 在进入锁以前自动引入自旋,这实际上是一种抢占式调度—preemptive scheduling),也可以通过runtime.Gosched()主动出让 CPU,调度器还可能无缘由地主动抢占 Goroutine 的时间片(比如已经运行了10ms)。因为是绿色线程,所以可以很便宜地创造百万Goroutine。在 Go 1.5 以后,可以通过 GOMAXPROCS 来使用更多的逻辑 CPU(而不也是系统进程)来利用多核。主线程不是主线程,主线程也是一个 main goroutine。
  2. Go 关键字基本就等同于 Java 中提交一个 Runnable 到 CompletableFuture 的 CommonPool。在没有 Channel 的帮助时,goroutine 几乎可以等同于一个绿色的守护线程。
  3. Go 也是有 mutex 的,但是不提倡使用,用 channel 最好。 share memory by communicating。
  4. channel 是通过描述若干操作的模式匹配来实现 select 的。它的无 buffer 版本和有 buffer版本类似于 SynchronousQueue 和 BlockingQueue。这个东西是化异步为同步的利器。default 和 timeout 可以让阻塞操作变为非阻塞的操作。channel 的阻塞也是会引起 Goroutine 的调度的。
  5. channel 是 CSP(Communicating Sequential Proceesses)模型的实现。
  6. 单向 channel 有点像泛型里的单边操作的 wildchar,可以封印掉读/写能力,而且需要通过声明强转。
  7. channel 可以被关闭。但关闭有什么用呢?不关闭它也会被垃圾回收,关闭只是 sender 给 reciever 发送的一个状态变化。
  8. 和其他方案的对比
    1. 异步回调会把程序拆得七零八落。人脑还是线性思维的。化异步为同步是最重要的。 Goroutine 就是化异步为同步的。
    2. GreenThread/Coroutine/Fiber方案 遇到阻塞的时候,可以自己 yield 出 CPU,但还是需要外部的线程把 context resume 回来。Go 则由 scheduler 自动识别代劳了。需要外部线程来不断切换 context,其实是一种单线程的并发,尽量减少阻塞时间而能够多利用 CPU 罢了。
    3. 因为有了遇到IO阻塞的时候自动 yield 的机制,所以其他机制中 M:1 或者 M:N 的时候,单线程可能会用 IO 系统调用阻塞整个进程的情况,不再发生。
  9. 调度器的细节:此处输入图片的描述此处输入图片的描述
    调度器就好像是一个分层调度的线程池。M 代表 物理处理器(其实是 machine 的意思),P 代表逻辑处理器,G 代表 Goroutine。Go 实现了 M:N 的调度(而不是1:M 的调度),G 通过 P(只看到P),可以在不同的 M 之间自由切换,这是其他 Green Thread 做不到的(因为其他 Green Thread 本质上还是但进程/系统线程)。G 可以阻塞,M永远不阻塞。这方面的出处见这里。注意看图,这里面还是用的工作窃取算法。调度器的细节可以查看《也谈goroutine调度器》
  10. 更多的例子见Go by Example《并发之痛 Thread,Goroutine,Actor》《Go 调度器: M, P 和 G》《golang大杀器GMP模型》