why golang sched runs differently when the variable is odd or even? Is it coincidence or doomed?

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

why golang sched runs differently when the variable is odd or even? Is it coincidence or doomed?

问题

我有一个golang代码示例,如下所示(xx.go):

package main

import "runtime"

func main() {
    c2 := make(chan int)

     go func() {
        for v := range c2 {
            println("c2 =", v, "numof routines:", runtime.NumGoroutine())
        }
    }()

    for i:=1;i<=10001;i++{
        c2 <- i
        //runtime.Gosched()
    }
}
  • 当循环次数是奇数时,比如10001,代码将输出所有的数字。
  • 当循环次数是偶数时,比如10000,代码将输出所有的数字除了最后一个

为什么会这样?

我已经测试了从2到10000的数字,它们都遵守上述规则!

环境如下:

uname -a : Linux hadoopnode25232 2.6.18-308.16.1.el5 #1 SMP Tue Oct 2 22:01:43 EDT 2012 x86_64 x86_64 x86_64 GNU/Linux

go version : go version go1.1 linux/amd64

我认为这与go调度有关。

我汇编了代码:

go tool 6g -S xx.go > xx.s

10000和10001之间唯一的区别是:

33c33
< 0030 (xx.go:20) CMPQ    AX,$10001
---
> 0030 (xx.go:20) CMPQ    AX,$10000

最后但并非最不重要的是,当我添加runtime.Gosched()时,一切都运行正常。

英文:

I have a sample of golang code as follows(xx.go):

package main

import &quot;runtime&quot;

func main() {
    c2 := make(chan int)

     go func() {
        for v := range c2 {
            println(&quot;c2 =&quot;, v, &quot;numof routines:&quot;, runtime.NumGoroutine())
        }
    }()

    for i:=1;i&lt;=10001;i++{
        c2 &lt;- i
        //runtime.Gosched()
    }
}
  • When the loop count is odd,say 10001,the code will output all the numbers.
  • when the loop count is even ,say 10000,the code will output all the numbers but the last!

Why is that?

I have tested numbers from as small as 2 to as large as 10000,they all obey the above rules!

the ENV is as follows:

uname -a : Linux hadoopnode25232 2.6.18-308.16.1.el5 #1 SMP Tue Oct 2 22:01:43 EDT 2012 x86_64 x86_64 x86_64 GNU/Linux

go version : go version go1.1 linux/amd64

I think it has something to do with the go sched.

I assemble the code:

go tool 6g -S xx.go &gt; xx.s

the only difference between 10000 and 10001 is :

33c33
&lt; 0030 (xx.go:20) CMPQ    AX,$10001
---
&gt; 0030 (xx.go:20) CMPQ    AX,$10000

And,last but not least, when I add runtime.Gosched(),everything runs well.

答案1

得分: 1

当主函数返回时,程序终止。它不会等待任何goroutine完成。因此,所有goroutine是否及时完成取决于调度器,以及一些随机性、巧合和外部因素。在1e4和1e4+1迭代之间的差异可能是影响调度的因素之一,正好使得goroutine及时完成。

如果你真的需要在退出之前完成goroutine,请等待它完成,例如使用sync.WaitGroup。

与实际问题无关,你的代码过于复杂,不符合惯用写法。你可以将goroutine函数重写如下:

for v := range c2 {
    println("c2 =", v, "numof routines:", runtime.NumGoroutine())
}
英文:

When main returns, the program terminates. It will not wait for any goroutines to finish. So whether all goroutines finish in time or not depends on the scheduler, and by extension on a fair bit of randomness, coincidence and external factors. The difference between 1e4 and 1e4+1 iterations might be one of those factors that affects the scheduling in just that one bit that makes the goroutine finish in time.

If you really require the goroutine to finish before exitting, wait for it to finish, by employing for example a sync.WaitGroup.

Unrelated to the actual issue, your code is overly complex and unidiomatic for what it's doing. You could rewrite the goroutine function as follows:

for v := range c2 {
    println(&quot;c2 =&quot;, v,&quot;numof routines:&quot;,runtime.NumGoroutine())
}

答案2

得分: 0

你需要睡眠一秒钟或者阻塞一段时间,等待goroutine完成!

英文:

You need sleep a second or block a while wait the goroutine is finish!!

答案3

得分: 0

> Go语句
>
> "go"语句启动一个函数调用的执行,作为一个独立的并发线程控制,或者称为goroutine,在同一个地址空间内。
>
> GoStmt = "go" Expression .
>
> 函数值和参数在调用的goroutine中按照通常的方式进行评估,但与常规调用不同,程序执行不会等待被调用的函数完成。

一旦最后的发送操作c2 &lt;- i完成,程序可以终止,不需要等待被调用的函数完成。你只能保证执行接收操作v, ok := &lt;-c2 c - 1 次,其中 c 是你的循环计数,即你的测试中的10000或10001次。

英文:

> Go statements
>
> A "go" statement starts the execution of a function call as an
> independent concurrent thread of control, or goroutine, within the
> same address space.
>
> GoStmt = "go" Expression .
>
> The function value and parameters are evaluated as usual in the
> calling goroutine, but unlike with a regular call, program execution
> does not wait for the invoked function to complete.

Once the final send, c2 &lt;- i, is complete the program may terminate, it does not have to wait for the invoked function to complete. You are only guaranteed to complete executing the receive, v, ok := &lt;-c2, c - 1 times, where c is your loop count, 10000 or 10001 in your tests.

huangapple
  • 本文由 发表于 2013年6月21日 11:25:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/17227225.html
匿名

发表评论

匿名网友

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

确定