Golang 协程
协程的特点
- 独立的栈空间
- 共享程序堆空间
- 调度由用户控制
- 协程是轻量级的线程
- 如果函数有返回值, 使用协程时, 返回值将被吞掉
案例
编写一个程序完成如下功能:
- 在主线程中,开启一个goroutine, 该协程每隔1秒输出“hello world”
- 在主线程中也每隔一秒输出“hello golang”, 输出10次
- 要求主线程和goroutine同时执行
func test(){
for i := 0; i < 10; i++ {
fmt.Println("hello world",i)
time.Sleep(time.Second)
}
}
func main() {
go test()
for i := 0; i < 10; i++ {
fmt.Println("hello golang", i)
time.Sleep(time.Second)
}
}
主线程和协程的执行流程图
与Java中的线程不同,Java如果没有设置守护线程,main线程需要在其他线程结束后才会退出
获取cpu核数
func main() {
//cp逻辑核数等同于Java中的Runtime.getRuntime().availableProcessors();
cpu := runtime.NumCPU()
fmt.Println(cpu)// 8
//设置运行的逻辑cpu个数, 并返回先前的配置
cpu = runtime.GOMAXPROCS(4)
fmt.Println(cpu)// 8
}
Goshced
func main() {
for i := 0; i < 5; i++ {
go func(i int) {
if i == 3 {
//相当于Java的yield
runtime.Gosched()
}
for j := 0; j < 10; j++ {
fmt.Println("task", i,"====>", j)
}
}(i)
}
for true {
}
}
/*~~~~~~~~~~~~~~~~~~~~~~*/
func main() {
//协程还没有启动主线程就已经跑完for, i大概率为5
for i := 0; i < 5; i++ {
go func(num int) {
//闭包可以访问外部的内容
if i == 3 {
//相当于Java的yield
runtime.Gosched()
}
for j := 0; j < 10; j++ {
fmt.Println("task", i,"====>", j)
}
}(100)
}
for true {
}
}
Goexit
func task(){
for i := 0; i < 10; i++ {
if i == 5 {
//主动退出当前运行的协程
runtime.Goexit()
}
fmt.Println(i)
}
}
func main() {
go task()
for true {
}
}
如果主线程主动退出, 子线程就会自己运行, 直到死锁
func task(){
for i := 0; i < 10; i++ {
fmt.Println("task",i)
}
}
func main() {
go task()
for i := 0; i < 10; i++ {
if i == 3 {
runtime.Goexit // 主线程主动退出
}
fmt.Println("main",i)
}
}