Golang:goroutine无限循环

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

Golang: goroutine infinite-loop

问题

当从上面的代码中删除fmt.Print()行时,代码会无限运行。为什么?

package main

import "fmt"
import "time"
import "sync/atomic"

func main() {
    var ops uint64 = 0
    for i := 0; i < 50; i++ {
        go func() {
            for {
                atomic.AddUint64(&ops, 1)
                fmt.Print()
            }
        }()
    }
    time.Sleep(time.Second)
    opsFinal := atomic.LoadUint64(&ops)
    fmt.Println("ops:", opsFinal)
}

当删除fmt.Print()行时,代码会无限运行的原因是,fmt.Print()函数在每次循环迭代时都会尝试读取标准输入,但是没有提供任何参数给它,因此它会一直等待输入。由于没有输入,代码就会陷入无限循环,无法继续执行下去。

英文:

When an fmt.Print() line is removed from the code below, code runs infinitely. Why?

package main

import &quot;fmt&quot;
import &quot;time&quot;
import &quot;sync/atomic&quot;

func main() {
        var ops uint64 = 0 
        for i := 0; i &lt; 50; i++ {
                go func() {
                        for {
                                atomic.AddUint64(&amp;ops, 1)
                                fmt.Print()
                        }
                }()
        }
        time.Sleep(time.Second)
        opsFinal := atomic.LoadUint64(&amp;ops)
        fmt.Println(&quot;ops:&quot;, opsFinal)
}

答案1

得分: 8

Go By Example文章包括

// 允许其他goroutine继续执行。
runtime.Gosched()

fmt.Print()起到了类似的作用,并允许main()有机会继续执行。

在无限循环的情况下,export GOMAXPROCS=2可能有助于程序完成,如在“golang: goroute with select doesn't stop unless I added a fmt.Print()”中所解释的那样。

> fmt.Print()明确地将控制权传递给一些syscall的内容


是的,go1.2+在调度程序中具有抢占功能

> 在之前的版本中,无限循环的goroutine可能会使同一线程上的其他goroutine饿死,当GOMAXPROCS只提供一个用户线程时,这是一个严重的问题。

> 在Go 1.2中,这部分得到了解决:调度程序在进入函数时会偶尔被调用。这意味着任何包含**(非内联)函数**调用的循环都可以被抢占,从而允许在同一线程上运行其他goroutine。

请注意我强调的部分:在你的示例中,for循环atomic.AddUint64(&amp;ops, 1)可能已经被内联。在那里没有抢占。


更新于2017年:Go 1.10将摒弃GOMAXPROCS

英文:

The Go By Example article includes:

   // Allow other goroutines to proceed.
   runtime.Gosched()

The fmt.Print() plays a similar role, and allows the main() to have a chance to proceed.

A export GOMAXPROCS=2 might help the program to finish even in the case of an infinite loop, as explained in "golang: goroute with select doesn't stop unless I added a fmt.Print()".

> fmt.Print() explicitly passes control to some syscall stuff


Yes, go1.2+ has pre-emption in the scheduler

> In prior releases, a goroutine that was looping forever could starve out other goroutines on the same thread, a serious problem when GOMAXPROCS provided only one user thread.

> In Go 1.2, this is partially addressed: The scheduler is invoked occasionally upon entry to a function. This means that any loop that includes a (non-inlined) function call can be pre-empted, allowing other goroutines to run on the same thread.

Notice the emphasis (that I put): it is possible that in your example the for loop atomic.AddUint64(&amp;ops, 1) is inlined. No pre-emption there.


Update 2017: Go 1.10 will get rid of GOMAXPROCS.

huangapple
  • 本文由 发表于 2014年8月1日 14:03:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/25073815.html
匿名

发表评论

匿名网友

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

确定