go语言中的可以通过go关键字方便的开启协程,协程相当于轻量级的线程。
一个程序启动便开启一个进程,一个进程至少有一个线程,也就是主线程。线程是CPU调度的基本单位,也就是说线程的挂起和运行是由内核统一调度的。
而协程则是在用户态的协程调度器调度,协程的调度不涉及用户态内核态的切换,所以协程间切换的开销要远远小于线程间切换的开销。
线程被创建时就会分配一个线程id和一些资源,比如固定大小的栈空间(默认大小是1M),线程间共享进程的堆空间。为什么每个线程有自己的栈空间呢?
因为函数间调用时,函数内部的变量就在栈上,多个线程同时调用同一个函数时,如果每个线程没有自己独立的栈空间,会导致函数调用数据的错乱。因为线程间共享全局数据和堆上的数据,所以线程使用时要加锁,保证独享资源。
之所以说协程比线程更轻量级,是因为以动态扩展的方式使用空间,创建之初比线程更小,初始只有2k大小,而线程是1M。
线程的创建需要系统资源,释放时要回收系统资源。协程的创建和销毁比起线程来说代价也就小的多。所以使用协程我们可以比线程更小的代价并行的执行多个函数或者方法,所以协程使用更灵活。
例:
package main
import (
"fmt"
"sync"
)
var wg = sync.WaitGroup{}
func main() {
wg.Add(5) //表示要等待5个协程结束,数值为 执行一次 wg.Done 相当于wg.Add(-1), 减到0 wg.Wait()停止等待
//开启5个协程 5个协程并发执行
for i := 0; i < 5; i++ {
go gorun(i)
}
wg.Wait()
}
func gorun(i int) {
fmt.Println("hello go ", i)
wg.Done()
}
goroutine 使用起来很简单方便,这个相比于C++而言要简便太多。