戈朗:为什么os.Exit不';不要在goroutines内工作
我有一个非常简单的算法研究计划。当成功来临时,goroutine应该通过os.Exit(0)关闭(结束)。我等了一天,两天。。。。什么?:) 下面是简单的代码戈朗:为什么os.Exit不';不要在goroutines内工作,go,goroutine,Go,Goroutine,我有一个非常简单的算法研究计划。当成功来临时,goroutine应该通过os.Exit(0)关闭(结束)。我等了一天,两天。。。。什么?:) 下面是简单的代码 package main import "os" func main() { for { go func() { os.Exit(0) }() } } 我的问题是: 为什么os.Exit不能终止goroutine 终止(停止)goroutine执行的正确方法是什么 游乐场:您可以通过从函数返回来终止g
package main
import "os"
func main() {
for {
go func() { os.Exit(0) }()
}
}
我的问题是:
游乐场:您可以通过从函数返回来终止goroutine。如果需要确保goroutine运行到完成,则需要等待goroutine完成。这通常通过
sync.WaitGroup
或通过通道同步goroutines来完成
在您的示例中,首先需要确保不可能产生无限多的goroutine。因为在main
和新的goroutine之间没有同步点,所以不能保证它们中的任何一个会在主循环运行时执行os.Exit
调用
等待任意数量的goroutine完成的通常方法是使用sync.WaitGroup
,这将确保它们在退出main
之前都已执行
wg := sync.WaitGroup{}
for i := 0; i < 10000; i++ {
wg.Add(1)
go func() { defer wg.Done() }()
}
wg.Wait()
fmt.Println("done")
wg:=sync.WaitGroup{}
对于i:=0;i<10000;i++{
工作组.添加(1)
go func(){defer wg.Done()}()
}
wg.Wait()
fmt.Println(“完成”)
您遇到了Go计划程序的一个棘手的角落。答案是,os.Exit
确实会导致整个进程退出,但按照您的方式,goroutines从未运行过
可能发生的情况是for循环不断将新的goroutine添加到可用goroutine列表中,但由于整个过程仅在一个OS线程中运行,Go调度器从未真正安排不同的goroutine,只是继续运行for循环,而没有运行任何您生成的goroutine。请尝试以下方法:
package main
import "os"
func main() {
for {
go func() { os.Exit(0) }()
func() {}()
}
}
如果你在运动场上运行它,它应该会工作(事实上)
好吧,上面的代码可以工作,而你的代码却不能工作,这一事实应该是相当神秘的。这样做的原因是Go调度程序实际上是非抢占的。这意味着,除非一个给定的goroutine自愿决定给调度器运行其他东西的选项,否则其他任何东西都不会运行
现在很明显,您从未编写过包含命令的代码,以使调度程序有机会运行。在编译代码时,Go编译器会自动将这些代码插入到代码中。下面是上述代码工作的关键:goroutine可能决定运行调度程序的一个时间是调用函数的时间。因此,通过添加func(){}()
调用(这显然不起任何作用),我们允许编译器添加对调度程序的调用,从而使代码有机会调度不同的goroutine。因此,其中一个派生的goroutine运行,调用os.Exit
,进程退出
编辑:如果编译器内联调用,函数调用本身可能不够充分(或者,在本例中,由于函数调用不执行任何操作,因此将其完全删除),另一方面,保证工作。执行死手或压井开关
package main
import (
"fmt"
"time"
"os"
)
const maxNoTickle = 50 // will bail out after this many no tickles
const maxWorking = 20 // pretendWork() will tickle this many times
const deadTicks = 250 // milliseconds for deadHand() to check for tickles
const reportTickles = 4 // consecutive tickles or no tickles to print something
var (
tickleMe bool // tell deadHand() we're still alive
countNoTickle int // consecutive no tickles
countGotTickle int // consecutive tickles
)
/**
* deadHand() - callback to kill program if nobody checks in after some period
*/
func deadHand() {
if !tickleMe {
countNoTickle++
countGotTickle = 0
if countNoTickle > maxNoTickle {
fmt.Println("No tickle max time reached. Bailing out!")
// panic("No real panic. Just checking stack")
os.Exit(0)
}
if countNoTickle % reportTickles == 0 {
// print dot for consecutive no tickles
fmt.Printf(".")
}
} else {
countNoTickle = 0
countGotTickle++
tickleMe = false // FIXME: might have race condition here
if countGotTickle % reportTickles == 0 {
// print tilda for consecutive tickles
fmt.Printf("~")
}
}
// call ourselves again
time.AfterFunc(deadTicks * time.Millisecond, deadHand)
}
/**
* init() - required to start deadHand
*/
func init() {
time.AfterFunc(250 * time.Millisecond, deadHand)
tickleMe = true
}
/**
* pretendWork() - your stuff that does its thing
*/
func pretendWork() {
for count := 0; count < maxWorking; count++ {
tickleMe = true // FIXME: might have race condition here
// print W pretending to be busy
fmt.Printf("W")
time.Sleep(100 * time.Millisecond)
}
}
func main() {
go workTillDone()
for {
// oops, program went loop-d-loopy
}
}
主程序包
进口(
“fmt”
“时间”
“操作系统”
)
const maxNoTickle=50//将在多次无痒之后退出
const maxWorking=20//invokeWork()将多次挠痒痒
const deadTicks=250//毫秒,用于deadHand()检查痒
const reportTickles=4//连续挠痒或没有挠痒来打印某物
变量(
tickleMe bool//告诉deadHand()我们还活着
countNoTickle int//连续无痒
countGotTickle int//连续挠痒
)
/**
*deadHand()-如果一段时间后没有人签入,则回调以终止程序
*/
func deadHand(){
如果!痒{
倒计时++
countGotTickle=0
如果countNoTickle>maxNoTickle{
fmt.Println(“达到无痒最长时间。退出!”)
//恐慌(“没有真正的恐慌,只是检查堆栈”)
操作系统退出(0)
}
如果countNoTickle%reportTickles==0{
//打印圆点,连续无痒感
格式打印F(“.”)
}
}否则{
计数=0
数痒++
tickleMe=false//FIXME:这里可能有竞争条件
如果CountGoTickle%reportTickles==0{
//打印tilda以连续挠痒痒
格式打印F(“~”)
}
}
//再打电话给我们自己
time.AfterFunc(死区信号*时间毫秒,死区信号)
}
/**
*init()-需要立即启动
*/
func init(){
time.AfterFunc(250*时间毫秒,死手)
挠痒痒=真
}
/**
*假装工作()-你的东西做它的事
*/
func工作(){
对于计数:=0;计数
你确定这就是原因吗?因为给定的代码对我来说很好。在任何情况下,您是否尝试过simplereturn
?我不知道您在哪里尝试过,但在我的计算机上,此代码没有完成。我不知道如何在goroutines中使用return
。goroutine中的所有计算和结果都不能是“返回”。go func(){return}()
?我知道(手动计算后)会丢失成功结果。。。因为操作系统