九、goroutine和channel
进程和线程
A)进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单元
B)线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位
C)一个进程可以创建和撤销多个线程,同一个进程中的多个线程之间可以并发执行
nginx是 进程 ----》Fork多个子进程 --》多线程 --》多进程程序
协程和线程
协程:独立的栈空间,共享堆内存,调度由用户自己控制,本质上有点类似于用户级线程,这些用户线程的调度也是自己实现的
线程:一个线程上可以跑多个协程,协程是轻量级的线程
线程分为用户态的线程和操作系统级别的线程
goroutine:
package main import ( "fmt" "time" ) func test(){ var i int for { fmt.Println(i) time.Sleep(time.Second) i++ } } func main(){ go test() for{ fmt.Println("i running in main") time.Sleep(time.Second) //必须要加上,防止main线程跑的太快看不清 } } 执行结果 D:\project>go build go_dev/day8/example D:\project>example i running in main 0 1 i running in main i running in main 2 3 i running in main i running in main 4 5 i running in main i running in main 6
goroutine调度模型
M:系统里面的线程
P:调度器
G:协程 goroutine
1)可以看出上面的每个操作系统线程有4个协程执行,只不过有3个协程是在队列中执行
2)可以看出一个线程可以多个协程在跑
在1.8之前可以把程序设置到init函数里面,1.8以上不用设置cpu的核心数
如何设置golang运行的cpu核数
package main import ( "runtime" "fmt" ) func main(){ num := runtime.NumCPU() //查找当前cpu的核心数量 runtime.GOMAXPROCS(num) //设置golang运行核数 这里结果为8 fmt.Println(num) } 运行结果 8
channel声明
var 变量名 chan 类型
var test chan int
var test chan string
var test chan map[string] string
var test chan stu
var test chan *stu
channl初始化使用make
变量名 = make (chan 类型 size)
创建map类型往channel里面添加数据
创建map类型往channel里面添加数据 package main func main(){ var mapchan chan map[string]string //声明channel mapchan = make(chan map[string]string ,10) //初始化channel m := make(map[string]string) //初始化map m["stu01"]="stu01" mapchan <- m //往channel里面添加数据 } 创建struct,往channel里面添加数据 package main type student struct{ name string } func main(){ var stuchan chan student stuchan = make(chan student,10) stu:=student{name:"stu01"} stuchan <- stu } 指针形式添加到channel package main type student struct{ name string } func main(){ var stuchan chan *student stuchan = make(chan *student,10) stu:=student{name:"stu01"} stuchan <- &stu }
channel超时处理
利用select来处理chan超时
for { select { case v := <-chan1: fmt.Println(v) case v := <-chan2: fmt.Println(v) default: time.Sleep(time.Second) fmt.Println("timeout...") } }
time.After()定时器来做处理。
在time.After()计时器触发之前,底层计时器不会被垃圾收集器回收。