Go語言 go程釋放操作(退出/銷毀)
情況1:
Go語言中,若在子go程中創建一個新 go程,子go程釋放(銷毀),新創建的go程不會隨著子go程的銷毀而銷毀。
原因:
go程共享堆,不共享棧,go程由程序員在go的代碼裡顯示調度(釋放)。
實例:
package main import ( "fmt" "time" "runtime" ) func test() { for i:=0;i<10;i++{ fmt.Printf("執行第%d次go程\n",i) time.Sleep(time.Second) } fmt.Println("go程執行完畢!") } func main() { go func() { go test() fmt.Println("------aaaaaaaa-------") time.Sleep(time.Second) fmt.Println("------go程結束--------------") /* 不管是return 還是 runtime.Goexit(),效果一樣 */ //return runtime.Goexit() }() for{ runtime.GC() } }
從以上實例來看,雖然子go程已經退出,但是在子go程中新建的go程還在執行!原因:go程不共享棧,有自己獨立的棧空間。子go程有自己的棧,在子go程中創建的新go程也有自己的棧。
子go程的棧被釋放(回收),由於棧獨立,因此新創建的go程的棧不會被釋放。
情況2:
Go語言中,若在主go程中創建一個新 go程,主go程釋放(銷毀),新創建的go程隨著主go程的銷毀而銷毀。
原因:
go程共享堆,不共享棧,go程由程序員在go的代碼裡顯示調度(釋放)。
實例:
package main import ( "fmt" "time" ) func main() { go func() { for i:=0;i<10;i++{ fmt.Printf("子go程:執行第%d次操作!\n",i) time.Sleep(time.Second) } }() for i:=0;i<3;i++{ fmt.Println("--------aaaa------") time.Sleep(time.Second) } }
從以上實例來看,雖然主go程退出,子go程馬上退出。原因:go程共享堆。主go程和新創建的子go程共享一個堆。主go程退出,執行main對應的{ },堆退出。由於是共享堆,所以對應的子go程也會被銷毀。
補充:go基礎之服務退出問題
最近學習公司微服務的代碼,看到每一個微服務的main函數都阻塞在那裡,然後裡面起的goroutine一直在哪裡運行。
package main import( "fmt" "os" "os/signal" "syscall" "log" "time" ) func testFunc() error { go func(){ for{ fmt.Printf("testing....\n") time.Sleep(time.Minute) } }() return nil } func exitFunc(){ fmt.Println("i am exiting!") } func main(){ logger := log.New(os.Stdout, "[TestGoroutine]", log.Lshortfile | log.Ldate | log.Ltime) //初始化日志 exit := make(chan os.Signal,10) //初始化一個channel signal.Notify(exit, syscall.SIGINT, syscall.SIGTERM) //notify方法用來監聽收到的信號 testFunc() sig := <-exit logger.Printf("%s",sig.String()) exitFunc() }
代碼輸出
[root@localhost demoproject]# go run test.go
testing….
^C[TestGoroutine]2018/07/31 19:26:14 test.go:36: interrupt
i am exiting!
可以看到知道按瞭ctrl+c之後才退出main函數的運行。然後goroutine隨之停止運行。
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。如有錯誤或未考慮完全的地方,望不吝賜教。
推薦閱讀:
- golang 中signal包的Notify用法說明
- Go項目實現優雅關機與平滑重啟功能
- Go並發編程中sync/errGroup的使用
- 解決go在函數退出後子協程的退出問題
- 幾個小技巧幫你實現Golang永久阻塞