zoukankan      html  css  js  c++  java
  • golang 中, os.exit() runtime.Goexit() return 有什么区别

    return结束当前函数,并返回指定值
    runtime.Goexit结束当前goroutine,其他的goroutine不受影响,主程序也一样继续运行
    os.Exit会结束当前程序,不管你三七二十一

    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的环境变量之一

    �6�7 当n<1:非法数字,方法不作修改

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

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

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

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

  • 相关阅读:
    Thymeleaf使用
    关闭被占用端口
    在map、model、modelAndView中存放数据 回显
    @RequestAttribute 注解
    @PathVariable、@RequestHeader、@RequestParam、@RequestBody 注解使用
    RESTful风格请求映射
    yml文件 数据回显
    JVM垃圾回收与一次线上内存泄露问题分析和解决过程
    比较java_io_Externalizable和Serializable
    关于java中的对象序列化
  • 原文地址:https://www.cnblogs.com/ExMan/p/14693893.html
Copyright © 2011-2022 走看看