最近渐渐深入golang,昨天听老师讲的深有感触,今天赶紧review一下。
为什么协程(gorutine)比线程(thread)快?
一、go协程比线程占用内存少
- 线程是内核对外提供的服务,应用程序可以通过系统调用让内核启动线程,由内核来负责线程调度和切换。
- golang 是自己实现的 MPG并发模型实现,协程直接的切换在用户态
执行go协程只需要极少的栈内存(大概是4~5KB),默认情况下,线程栈的大小为1MB。
goroutine就是一段代码,以及在堆上为其分配的一个堆栈。非常廉价,可以很轻松的创建上万个goroutine,它并不是被操作系统所调度执行。
二、协程之间的切换 成本开销小
因为线程是内核级别,通过系统调用的方式切换线程。线程在等待IO操作时线程变为unrunnable状态会触发上下文切换, CPU需要记录线程的现场状态,然后把CPU分配给其他线程运行,在CPU访问内存时,会有一份虚拟地址到物理地址的缓存TLB,线程直接的切换会每次进行刷新该表
go协程也叫用户态线程,协程之间的切换发生在用户态。在用户态没有时钟中断,系统调用等机制,因此效率高
线程每次进行切换,TLB都要进行一次刷新
三、总结
1、减少了线程切换的成本。Java 中的线程,不管是创建还是切换,都需要较高的成本。子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。这也就是说,协程的效率比较高。
2、协程的第二大优势就是,不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。
3、协程更轻量级。创建一个线程栈大概需要 1M 左右,而协程栈大概只需要几 K 或者几十 K。