简体   繁体   English

为什么添加time.sleep时我的程序挂起?

[英]Why does my program hang when adding time.sleep?

I am trying to make a test for my program that will save to the disk over a set interval. 我正在尝试对我的程序进行测试,该程序将在设定的时间间隔内保存到磁盘。 My problem is when I add time.Sleep to the test, no matter the duration, the program hangs. 我的问题是当我增加时间时,请休眠测试,无论持续时间长短,程序都会挂起。

My expected behavior would be that I allow it to sleep, and the go routine should run in the background for that duration saving to the disk. 我的预期行为是我允许它进入睡眠状态,并且go例程应该在后台运行,以将这段时间保存到磁盘中。

Here is the function in question that is being run as a goroutine from the test. 这是有问题的功能,正在从测试中作为goroutine运行。

nodeservice.go nodeservice.go

func runRegistryBackup(reg *NodeRegistry, interval int, killchan chan bool) {
log.SetPrefix("[Registry Backup]\t")
log.Printf("Intializing backup every %d seconds", interval)
select {
case <-time.Tick(time.Duration(interval) * time.Second):
    log.Println("Backing up node registry to disk")
    reg.write()
case <-killchan:
    log.Println("Flushing data to disk")
    reg.write()
    defer func() { killchan <- true }()
    //defer close(killchan)
    return
}

} }

And here is the test. 这是测试。 I commented the line that when added will freeze the program 我评论了添加后将冻结程序的行

nodeservice_test.go nodeservice_test.go

func TestRunRegistry(t *testing.T) {
// need registry, interval, bool chan

// setup
fi, _ := ioutil.TempFile("", "msg-serv-test-")
defer os.Remove(fi.Name())
reg := MakeNodeRegistry(fi.Name())
name := "test"
ip := "10.0.0.1"
port := "0"
tls := false
node1 := MakeNode(name, ip, port, tls)
reg.addNode(node1)

interval := 5
kill := make(chan bool)

// test the interval
go runRegistryBackup(reg, interval, kill)
// let run for a little
time.Sleep(time.Minute) // adding this line hangs the whole program
// test kill
kill <- true
<-kill

actReg := BuildRegistry(fi.Name())

for key, eval := range reg.Nodes {
    val := actReg.Nodes[key]
    if eval != nil && val != nil {
        assert(t, *val, *eval)
    } else {
        t.Logf("Expected Hash: %d \t Expected Node: %v", key, eval)
        t.Logf("Key %d not found for Node %v", key, val)
        t.Fail()
    }

}

} }

Here is the output of the log that shows that the interval is only being run once and then hanging. 这是日志的输出,显示该间隔仅运行一次然后挂起。

[Registry Backup]       2019/07/19 13:29:51 Intializing backup every 5 seconds
[Registry Backup]       2019/07/19 13:29:56 Backing up node registry to disk

Any insight as to the cause of this problem would be greatly appreciated. 任何有关此问题的原因的见解将不胜感激。

The function runRegistryBackup calls write() once and then exits. 函数runRegistryBackup调用一次write() ,然后退出。 The main goroutine then blocks on sending to kill . 然后,主要goroutine阻止发送kill

Fix by adding a loop to the function. 通过向函数添加循环进行修复。 Create the ticker once before the loop and stop the ticker when returning. 在循环之前创建一个代码,并在返回时停止代码。

func runRegistryBackup(reg *NodeRegistry, interval int, killchan chan bool) {
    log.SetPrefix("[Registry Backup]\t")
    log.Printf("Intializing backup every %d seconds", interval)
    t := time.NewTicker(time.Duration(interval) * time.Second)
    defer t.Stop()
    for {
        select {
        case <-t.C:
            log.Println("Backing up node registry to disk")
            reg.write()
        case <-killchan:
            log.Println("Flushing data to disk")
            reg.write()
            defer func() { killchan <- true }()
            return
        }
    }
}

The unbuffered kill channel adds some fragility to the program. 无缓冲的kill通道为程序增加了一些脆弱性。 For example, if runRegistryBackup is modified to exit on a write error and main attempts to kill the backup after that error, then main will block forever. 例如,如果将runRegistryBackup修改为在发生写错误时退出,并且main尝试在该错误之后runRegistryBackup备份,则main将永远阻塞。 Fix by making the channel buffered. 通过缓冲通道进行修复。

kill := make(chan bool, 1)

go runRegistryBackup(reg, interval, kill) return with case <-time.Tick Nothing can read from kill channel, so main routine blocks on kill <- true . go runRegistryBackup(reg, interval, kill)返回与case <-time.Tick没有任何东西可以从杀信道读取,因此主例程块上kill <- true I don't exactly understand your program's logic, so the easiest way to get things work is to make kill channel buffered 我不完全了解您的程序的逻辑,因此让事情正常工作的最简单方法是使kill channel缓冲

kill := make(chan bool, 1)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM