• 浅析runtime包中的三个方法Gosched、Goexit、GOMAXPROCS


    Gosched

    暂停当前goroutine,使其他goroutine先行运算。只是暂停,不是挂起,当时间片轮转到该协程时,Gosched()后面的操作将自动恢复

    未使用Gosched的代码
    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	go output("goroutine 2")
    	
    	output("goroutine 1")
    }
    
    func output(s string){
    	for i:=0;i<3;i++{
    		fmt.Println(s)
    	}
    }
    
    输出
    goroutine 1
    goroutine 1
    goroutine 1
    

    结论:还没等到子协程执行,主协程就已经执行完退出了,子协程将不再执行,所以打印的全部是主协程的数据。当然,实际上这个执行结果也是不确定的,只是大概率出现以上输出,因为主协程和子协程间并没有绝对的顺序关系

    使用Gosched的代码
    package main
    
    import (
    	"fmt"
    	"runtime"
    )
    
    func main() {
    	go output("goroutine 2")
    
    	runtime.Gosched()
    	output("goroutine 1")
    }
    
    func output(s string){
    	for i:=0;i<3;i++{
    		fmt.Println(s)
    	}
    }
    
    输出
    goroutine 2
    goroutine 2
    goroutine 2
    goroutine 1
    goroutine 1
    goroutine 1
    

    结论:在打印goroutine 1之前,主协程调用了runtime.Gosched()方法,暂停了主协程。子协程获得了调度,从而先行打印了goroutine 2。主协程不是一定要等其他协程执行完才会继续执行,而是一定时间。如果这个时间内其他协程没有执行完,那么主协程将继续执行,例如以下例子

    使用Gosched的代码,并故意延长子协程的执行时间,看主协程是否一直等待
    package main
    
    import (
    	"fmt"
    	"runtime"
    	"time"
    )
    
    func main() {
    	go func() {
    		time.Sleep(5000)
    		output("goroutine 2")
    	}()
    
    	runtime.Gosched()
    	output("goroutine 1")
    }
    
    func output(s string) {
    	for i := 0; i < 3; i++ {
    		fmt.Println(s)
    	}
    }
    
    输出
    goroutine 1
    goroutine 1
    goroutine 1
    

    Goexit

    立即终止当前协程,不会影响其它协程,且终止前会调用此协程声明的defer方法。由于Goexit不是panic,所以recover捕获的error会为nil

    当main方法所在主协程调用Goexit时,Goexit不会return,所以主协程将继续等待子协程执行,当所有子协程执行完时,程序报错deadlock

    package main
    
    import (
    	"fmt"
    	"runtime"
    	"time"
    )
    
    func main() {
    	go func(){
    		defer func(){
    			fmt.Println("defer func executed!")
    			fmt.Println("recovered error == ",recover())
    		}()
    
    		for i:=0;i<3;i++{
    			if i==1{
    				runtime.Goexit()
    			}
    
    			fmt.Println(i)
    		}
    	}()
    
    	time.Sleep(2*time.Second)
    }
    
    输出
    0
    defer func executed!
    recovered error ==  <nil>
    

    GOMAXPROCS(n int) int

    设置可同时执行的逻辑Cpu数量,默认和硬件的线程数一致而不是核心数,可以通过调用GOMAXPROCS(-1)来获取当前逻辑Cpu数

    最好在main函数之前设置它,GOMAXPROCS同时也是go的环境变量之一

    ​ 当n<1:非法数字,方法不作修改

    ​ 当n==1:单核心,多协程并发执行,并发只是看起来是同时执行的,实际上是同一时刻只有一个协程在跑,只是由于cpu的任务调度算法,让多个协程在效果上同时执行

    ​ 当n>1:多核心,多协程并行执行,并行一定是并发,不同的核心同时地跑不同的协程

    想要了解更多有关并发(Concurrency)和并行(Parallel)的区别,可以看看大神Rob Pike的视频Concurrency Is Not Parallelism,里面有很详细的讲解

    作者:胡金生
    出处:www.aprilboy.com
    版权所有,欢迎保留原文链接进行转载:)

    www.aprilboy.com
  • 相关阅读:
    笔记手动排序
    笔记手动分页
    Spring定时任务Quartz配置之手动设置
    java 日期处理
    SQL Case when 的使用方法
    Hibernate八大类HQL查询集合
    Spring定时任务Quartz配置
    各个浏览器显示版本(IE,火狐)
    js转译html标签
    定时备份SQL SERVER的数据库并且把备份文件复制到另外一台服务器
  • 原文地址:https://www.cnblogs.com/SpiderShrimp/p/11416208.html
Copyright © 2020-2023  润新知