Golang:为什么os.Exit在goroutines中不起作用 [英] Golang: Why os.Exit doesn't work inside goroutines

查看:522
本文介绍了Golang:为什么os.Exit在goroutines中不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个非常简单的算法研究程序。当goroutine成功时应该通过os.Exit(0)关闭(结束)。我等一天,两天......什么? :)



以下是简单的代码:

pre $

$ import func(){os.Exit(0)}()$ b $
$ b $ func main(){
b}
}

我的问题:


  1. 为什么os.Exit不会终止goroutine?

  2. 什么是终止goroutine execute的正确方法?

游乐场: http: //play.golang.org/p/GAeOI-1Ksc

解决方案

你碰到了一个粘滞的角落Go调度程序。答案是 os.Exit does 会导致整个进程退出,但是你的方式,goroutine永远不会运行。



可能发生的情况是for循环不断增加新的goroutines到可用的goroutine列表中,但由于整个过程只在一个OS线程中运行,Go调度程序从未得到实际上安排了一个不同的goroutine,并且不停地运行那个for循环,而没有运行任何你产生的goroutine。试试这个:

  package main 

importos

func main(){
for {
go func(){os.Exit(0)}()
func(){}()
}
}

如果您在Go Playground上运行它,它应该可以工作(事实上,这里有一个链接)。



好的,上面的代码工作,而你的不应该很神秘。这样做的原因是Go调度程序实际上是非抢占式的。这意味着,除非给定的goroutine自愿决定让调度程序选择运行其他方法,否则其他方法都不会运行。

现在显然您从来没有编写过包含命令给调度程序运行机会的代码。会发生的是,当你的代码被编译时,Go编译器会自动将这些代码插入你的代码中。下面是上述代码工作原理的关键:goroutine可能决定运行调度程序的时间之一是调用函数的时间。因此,通过添加 func(){}()调用(显然什么都不做),我们已经允许编译器在调用中添加一个调用,有机会安排不同的食堂。因此,其中一个产生的goroutine运行,调用 os.Exit ,并且进程退出。



编辑:在编译器内联函数的情况下(或者在这种情况下,由于它什么都不做),函数调用本身可能是不够的。 runtime.Gosched() ,on另一方面,保证工作。


I have a research program with very simple algorithm. When success is coming goroutine should be close (end) via os.Exit(0). I'm wait one day, two day.... What? :)

Here is the simple code

package main

import "os"

func main() {
    for {
        go func() { os.Exit(0) }()
    }
}

And my questions:

  1. Why os.Exit doesn't terminate the goroutine?
  2. What is correct way to terminate (stop) goroutine execute?

Playground: http://play.golang.org/p/GAeOI-1Ksc

解决方案

You've run into a sticky corner of the Go scheduler. The answer is that os.Exit does cause the entire process to exit, but the way you had it, the goroutines were never running.

What probably happened was that the for loop kept adding new goroutines to the list of available goroutines, but since the entire process was only running in one OS thread, the Go scheduler never got around to actually scheduling a different goroutine, and just kept running that for loop without ever running any of the goroutines you'd spawned. Try this instead:

package main

import "os"

func main() {
    for {
        go func() { os.Exit(0) }()
        func() {}()
    }
}

If you run it on the Go Playground, it should work (in fact, here's a link).

OK, the fact that the above code works while yours doesn't should be pretty mysterious. The reason this works is that the Go scheduler is actually non-preempting. What that means is that unless a given goroutine voluntarily decides to give the scheduler the option to run something else, nothing else will run.

Now obviously you've never written code that includes commands to give the scheduler a chance to run. What happens is that when your code is compiled, the Go compiler automatically inserts these into your code. And here's the key to why the above code works: one of the times that a goroutine might decide to run the scheduler is when a function is called. So by adding the func() {}() call (which obviously does nothing), we've allowed the compiler to add in a call to the scheduler, giving this code the opportunity to schedule different goroutines. Thus, one of the spawned goroutines runs, calls os.Exit, and the process exits.

EDIT: The function call itself may not be sufficient in the event that the compiler inlines the call (or, in this case, removes it entirely since it does nothing). runtime.Gosched(), on the other hand, is guaranteed to work.

这篇关于Golang:为什么os.Exit在goroutines中不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆