4.1 goroutine
goroutine使用go关键字来调用函数,也可以使用匿名函数。可以简单的把go关键字调用的函数想像成pthread_create。如果一个goroutine没有被阻塞,那么别的goroutine就不会得到执行。也就是说goroutine阻塞时,Golang会切换到其他goroutine执行,这是非常好的特性!Java对类似goroutine这种的协程没有原生支持,像Akka最害怕的就是阻塞。因为协程不等同于线程,操作系统不会帮我们完成“现场”保存和恢复,所以要实现goroutine这种特性,就要模拟操作系统的行为,保存方法或函数在协程“上下文切换”时的Context,当阻塞结束时才能正确地切换回来。像Kilim等协程库利用字节码生成,能够胜任,而Akka完全是运行时的。
注意:如果你要真正的并发,需要调用runtime.GOMAXPROCS(CPU_NUM)设置。
package main
import "fmt"
func main() {
go f("goroutine")
go func(msg string) {
fmt.Println(msg)
}("going")
// Block main thread
var input string
fmt.Scanln(&input)
fmt.Println("done")
}
func f(msg string) {
fmt.Println(msg)
}
4.2 原子操作
像Java一样,Golang支持很多CAS操作。运行结果是unsaftCnt可能小于200,因为unsafeCnt++在机器指令层面上不是一条指令,而可能是从内存加载数据到寄存器、执行自增运算、保存寄存器中计算结果到内存这三部分,所以不进行保护的话有些更新是会丢失的。
package main
import (
"fmt"
"time"
"sync/atomic"
"runtime"
)
func main() {
// IMPORTANT!!!
runtime.GOMAXPROCS(4)
// thread-unsafe
var unsafeCnt int32 = 0
for i := 0; i < 10; i++ {
go func() {
for i := 0; i < 20; i++ {
time.Sleep(time.Millisecond)
unsafeCnt++
}
}()
}
time.Sleep(time.Second)
fmt.Println("cnt: ", unsafeCnt)
// CAS toolkit
var cnt int32 = 0
for i := 0; i < 10; i++ {









