在Golang变量中,两个时间段的乘积为零。

huangapple go评论73阅读模式
英文:

Product of two time duration is zero in a Golang variable

问题

在下面的Golang代码中,奇怪的是两个时间持续时间的乘积在变量'delay'中为零,但是当直接打印乘积而不经过任何变量时,输出结果是预期的。有人能解释一下吗?

func StartCleanTask() {
    go func() {
        delay := cfg.Config.Timeout * time.Second
        for {
            fmt.Println("Go clean task: ", delay, cfg.Config.Timeout*time.Second)
            select {
            case <-time.After(cfg.Config.Timeout * time.Second):
                clean()
            }
        }
    }()
}

输出结果为:

Go clean task: 0 5m0s

更新:

我还尝试运行了以下代码,它运行良好。

package main

import "fmt"
import "time"

func main() {

    var timeout time.Duration
    timeout = 100
    delay := timeout * time.Second

    fmt.Println("Go clean task: ", delay, timeout*time.Second)

}

再次更新:

Paul的答案被接受。实际上,StartCleanTask()在cfg包的init函数中被调用,并且cfg.Config.Timeout在main函数中被赋予了一个指定的值。但是我忽略了包的init()函数在main()之前被隐式调用,所以变量delay始终为零。

顺便说一下,我不明白为什么有些人给这个问题打负分。我认为其他人可能会遇到类似的问题,这篇文章对于那些真正不了解init()和main()之间调用顺序的受害者应该是有帮助的。

英文:

It's weird in below Golang code that product of two time duration is zero in variable 'delay', but when print the product directly without through any variable, the output is as expected. Anyone can explain this?

 func StartCleanTask() {
  go func() {
       delay := cfg.Config.Timeout * time.Second
       for {
           fmt.Println(&quot;Go clean task: &quot;, delay, cfg.Config.Timeout*time.Second)
           select {
           case &lt;-time.After(cfg.Config.Timeout * time.Second):
               clean()
           }
     }
  }()

}

The output is:

 Go clean task: 0 5m0s

Update:

I also attempted to run following code, it works well.

package main 
import &quot;fmt&quot;
import &quot;time&quot;

func main() {

   var timeout time.Duration
   timeout = 100
   delay := timeout * time.Second

   fmt.Println(&quot;Go clean task: &quot;, delay, timeout*time.Second)

}

Update again:

Paul's answer is accepted. Actually StartCleanTask() is invoked in the init function of cfg package, and cfg.Config.Timeout is assigned to a specified value in main function. BUT I ignored that package's init() function is invoked implicitly before main(), so the variable delay is always ZERO.

BTW, I don't understand why some people give negative score to this question. I think others may hit similar problem, and this post should be helpful to the victim who don't really know the calling sequence between init() and main().

答案1

得分: 2

我猜测你正在并发地更新cfg.Config.Timeout,可能是这样的:

func main() {
    StartCleanTask()
    cfg.Config.Timeout = 300
    ...
}

这引入了一个竞争条件,因为在StartCleanTask内部的goroutine中,delayTimeout初始化之前被赋值,而fmt.Println发生在初始化之后。

你可以使用竞争检测器来查看是否存在这个问题。

假设cfg只被初始化一次,可能正确的修复方法是在初始化完成后才启动清理任务。

英文:

My guess is that you're updating cfg.Config.Timeout concurrently to this task. Perhaps like this:

func main() {
    StartCleanTask()
    cfg.Config.Timeout = 300
    ...
}

This introduces a race, and it happens that in the goroutine inside StartCleanTask, delay is assigned before the Timeout is initialized, and the fmt.Println happens after the initialization.

You can use the race detector to see if this is the problem.

Assuming that cfg is only initialized once, probably the right fix is to only start the cleanup task once the initialization has finished.

huangapple
  • 本文由 发表于 2016年3月5日 16:31:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/35811913.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定