说到Go的高并发能力,指的就是Go的协程,我们先讨论一个问题,为什么需要协程?
多进程或多线程
大家知道现在的CPU发展方向是多核,最新的AMD的民用级CPU已经达到了16核32线程,但是大部分编程语言只支持单核,这导致大部分应用无法充分利用多核CPU,所以有“一核有难,多核围观”这种说法。
不过,操作系统实际上是提供了多进程和多线程这2种利用多核CPU的方式,但是大部分编程语言支持也并不好,比如PHP,虽然有相关的扩展,但是实际上使用的人很少。
现在的Linux和Windows都是分时复用的多任务操作系统,上面跑着很多程序,所以操作系统需要在不同进程之间切换,这时候就产生了CPU上下文切换,毕竟CPU核数有限。默认情况下Linux只可以创建1024个进程,虽然可以修改配置,但是依然无法避免进程的创建和切换开销,多线程虽然更轻量级,但是依然存在该问题。
用户态线程
package mainimport"fmt"func main() {go func() {fmt.Println("Hello World")}()go say()}func say() {fmt.Println("Say")}package mainimport ("fmt""time")func main() {go func() {fmt.Println("Hello World")}()go say()time.Sleep(time.Second* 1) //睡眠1s}func say() {fmt.Println("Say")}//运行结果:/**Hello WorldSay*/package mainimport ("fmt""time")func main() {go say(1)go say(2)go say(3)go say(4)time.Sleep(time.Second* 1)}func say(iint) {fmt.Printf("Say: %d\n", i)}//运行结果:/**Say: 1Say: 4Say: 2Say: 3*/package mainimport ("fmt""time")func main() {//runtime.GOMAXPROCS(1) //模拟单核CPUvar num = 0go func(num *int) {fori := 0; i < 10000; i++ {add(num)}}(&num)go func(num *int) {fori := 0; i < 10000; i++ {add(num)}}(&num)time.Sleep(time.Second* 1)fmt.Println(num)}//引用传递funcadd(i *int) {*i = *i + 1}package mainimport ("fmt""sync")var wg = sync.WaitGroup{} //声明一个全局的对象func main() {wg.Add(4) //表示有4个协程需要执行go say(1)go say(2)go say(3)go say(4)wg.Wait() //等待}func say(iint) {fmt.Printf("Say: %d\n", i)wg.Done() //协程执行结束,-1}package mainimport ("fmt")func main() {var c = make(chanint)go say(1, c)go say(2, c)go say(3, c)go say(4, c)var i = 0for{select{case<-c:i++if i == 4 {close(c)return}}}}func say(iint, c chanint) {fmt.Printf("Say: %d\n", i)c <- i}