go语言并发模型 -- MPG
M: machine 系统线程
P: Processer 逻辑处理器
G: goroutine go语言协程
一个M会对应一个内核线程,一个M也会连接一个上下文P,一个上下文P相当于一个“处理器”
一个上下文连接一个或者多个Goroutinue。为了运行goroutine,线程必须保存上下文
运行的M和P的关系 1:1
一个调度器P 对应着一个本地队列
全局队列
本地队列满了 会把G放到全局队列中
hand off机制:
1.如果发生syscall处理的线程M0陷入阻塞状态,这个M0就会释放P
P就转移给空闲的M1去执行,如果没有空闲的线程,就会创建一个新线程执行
2.如果系统调用结束,根据M0是否获取到P,将会对原来的G做不同处理
a、如果有空闲的P,则获取一个P,继续执行原来的G0
b、如果没有空闲的P,将原来的G0加入全局队列,等待被其他的P调度,M0进入缓存池睡眠
全局队列任务处理
1、P运行完成自己的本地队列任务,就会从全局队列中拿取
2、P也会周期性这个全局队列,防止全局队列的goroutinue被饿死
work stealing机制
当本线程没有可运行的G的时候,可以从全局队列中获取G;
如果全局队列中也没有,就从别的线程绑定的P那里,抽取一半的G处理
sysmon monitor 协程 系统监控协程,监控公平性
不需要P也能执行,是一个特殊的协程,做协程监控的
在go中,一个协程,最多占用 cpu 10ms,防止其他 goroutines 饿死
任何超过10ms的协程,都会被抢占,将运行时间留给其他 goroutine
主要做协程抢占、垃圾回收
package main
import (
"fmt"
"time"
)
/*
go语言并发模型 -- MPG
M: machine 系统线程
P: Processer 逻辑处理器
G: goroutine go语言协程
一个M会对应一个内核线程,一个M也会连接一个上下文P,一个上下文P相当于一个“处理器”
一个上下文连接一个或者多个Goroutinue。为了运行goroutine,线程必须保存上下文
运行的M和P的关系 1:1
一个调度器P 对应着一个本地队列
全局队列
本地队列满了 会把G放到全局队列中
hand off机制:
1.如果发生syscall处理的线程M0陷入阻塞状态,这个M0就会释放P
P就转移给空闲的M1去执行,如果没有空闲的线程,就会创建一个新线程执行
2.如果系统调用结束,根据M0是否获取到P,将会对原来的G做不同处理
a、如果有空闲的P,则获取一个P,继续执行原来的G0
b、如果没有空闲的P,将原来的G0加入全局队列,等待被其他的P调度,M0进入缓存池睡眠
全局队列任务处理
1、P运行完成自己的本地队列任务,就会从全局队列中拿取
2、P也会周期性这个全局队列,防止全局队列的goroutinue被饿死
work stealing机制
1.当本线程没有可运行的G的时候,可以从全局队列中获取G;
如果全局队列中也没有,就从别的线程绑定的P那里,抽取一半的G处理
sysmon 系统监控协程,监控公平性
不需要P也能执行,是一个特殊的协程,做协程监控的,在go中,一个协程,最多占用 cpu 10ms
防止其他 goroutines 饿死,在任何超过10ms的协程,都会被抢占,将运行时间留给其他 goroutine
主要做协程抢占、垃圾回收
}
*/
// // 匿名协程
// func main() {
// go func() {
// i := 0
// for {
// i++
// fmt.Println("子协程 i=", i)
// time.Sleep(1 * time.Second)
// }
// }()
// for i := 0; i < 3; i++ {
// fmt.Println("主协程i=", i)
// time.Sleep(1 * time.Second)
// }
// }
package main
import (
"fmt"
"time"
)
/*
go语言并发模型 -- MPG
M: machine 系统线程
P: Processer 逻辑处理器
G: goroutine go语言协程
一个M会对应一个内核线程,一个M也会连接一个上下文P,一个上下文P相当于一个“处理器”
一个上下文连接一个或者多个Goroutinue。为了运行goroutine,线程必须保存上下文
运行的M和P的关系 1:1
一个调度器P 对应着一个本地队列
全局队列
本地队列满了 会把G放到全局队列中
hand off机制:
1.如果发生syscall处理的线程M0陷入阻塞状态,这个M0就会释放P
P就转移给空闲的M1去执行,如果没有空闲的线程,就会创建一个新线程执行
2.如果系统调用结束,根据M0是否获取到P,将会对原来的G做不同处理
a、如果有空闲的P,则获取一个P,继续执行原来的G0
b、如果没有空闲的P,将原来的G0加入全局队列,等待被其他的P调度,M0进入缓存池睡眠
全局队列任务处理
1、P运行完成自己的本地队列任务,就会从全局队列中拿取
2、P也会周期性这个全局队列,防止全局队列的goroutinue被饿死
work stealing机制
1.当本线程没有可运行的G的时候,可以从全局队列中获取G;
如果全局队列中也没有,就从别的线程绑定的P那里,抽取一半的G处理
sysmon 系统监控协程,监控公平性
不需要P也能执行,是一个特殊的协程,做协程监控的,在go中,一个协程,最多占用 cpu 10ms
防止其他 goroutines 饿死,在任何超过10ms的协程,都会被抢占,将运行时间留给其他 goroutine
主要做协程抢占、垃圾回收
}
*/
// // 匿名协程
// func main() {
// go func() {
// i := 0
// for {
// i++
// fmt.Println("子协程 i=", i)
// time.Sleep(1 * time.Second)
// }
// }()
// for i := 0; i < 3; i++ {
// fmt.Println("主协程i=", i)
// time.Sleep(1 * time.Second)
// }
// }
创建一个协程
package main
import (
"fmt"
"runtime"
"time"
)
/*
协程
运行main,就是运行了一个协程,运行之初就创建一个协程
协程 -- runtime.g 结构体
*/
func main() {
fmt.Println("hello word")
//GOMAXPROCS 设置当前P的数量 输入0表示查询当前P的数量,输入大于0的数,表示设置P的数量
fmt.Println(runtime.GOMAXPROCS(0)) //8
runtime.GOMAXPROCS(9)
fmt.Println(runtime.GOMAXPROCS(0)) //9
go hello() //开启协程
go hello2()
//默认情况下,主协程退出,子协程也会退出
time.Sleep(2 * time.Second)
}
func hello() {
fmt.Println("hello start...")
fmt.Println("hello end...")
}
func hello2() {
fmt.Println("hello2 start...")
time.Sleep(1 * time.Second)
fmt.Println("hello2 end...")
}
匿名协程
package main
import (
"fmt"
"time"
)
// 匿名协程
func main() {
go func() {
i := 0
for {
i++
fmt.Println("子协程 i=", i)
time.Sleep(1 * time.Second)
}
}()
for i := 0; i < 3; i++ {
fmt.Println("主协程i=", i)
time.Sleep(1 * time.Second)
}
}
协程异常处理
//协程异常处理
//go语言中,如果一个协程崩溃了,所有协程都会退出
package main
import (
"fmt"
"time"
)
func except_test() {
defer func() {
if r := recover(); r != nil {
fmt.Println("something error!", r)
}
}()
fmt.Println("this is except_test")
lst := []int{1, 2, 3}
fmt.Println(lst[3])
}
func except_test2() {
fmt.Println("this is except_test2")
time.Sleep(1 * time.Second)
fmt.Println("except_test2 end...")
}
func main() {
fmt.Println("this is main")
go except_test()
go except_test2()
time.Sleep(2 * time.Second)
fmt.Println("end...")
}
多个协程下载照片
// 多个协程下载多张图片
package main
import (
"fmt"
"time"
)
func Download_photo() {
fmt.Println("下载照片")
}
func main() {
for i := 0; i < 5; i++ {
go Download_photo()
time.Sleep(1 * time.Second)
}
}
sync锁机制
package main
import (
"fmt"
"sync"
"time"
)
/*
go语言sync包 提供了一些用于并发操作的同步原语
常见的锁机制
互斥锁 mutex
条件变量 cond
WaitGroup 阻塞
*/
var wg sync.WaitGroup
var num = 10
var mutex sync.Mutex
func main() {
wg.Add(3)
go test(&wg)
go test(&wg)
go test(&wg)
wg.Wait() //主协程等待子协程
fmt.Println("执行结束")
}
func test(wg *sync.WaitGroup) {
defer wg.Done()
mutex.Lock()
time.Sleep(1 * time.Second)
fmt.Println("this is test")
num += 1
fmt.Println("num:", num)
mutex.Unlock()
}