Google Go的goroutine中断模式(速度问题)

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

interrupt pattern for google go goroutine (speed issue)

问题

我运行了一个goroutine来递增一个计数器,可以通过命令行输入"t"来中断。

select语句中,如果我选择使用default:,计数器变量j会不断增加。这对我来说看起来很正常。

然而,如果我选择使用case <-time.After(100*time.Microsecond):,计数器j在一秒钟内只增加到大约60左右,而不是10,000。

实际上,无论我在time.After()中放入什么值,我只能得到大约60Hz的速率通过select语句运行。

为什么会这样?

package main
import (
	"bufio"
	"fmt"
	"os"
	"strings"
	"time"
)

func main() {
	message := make(chan string)
	go check_input(message)
	work_loop(message)
}

func work_loop(message chan string) {
	//var j [][]int
	var j int
	t0:=time.Now()
Loop:
	for {
		select {
		case msg := <-message:
			if msg == "terminate" {
				//fmt.Println("end task")
				t1:=time.Now()
				fmt.Println(j)
				fmt.Println("total duration:", t1.Sub(t0))
				break Loop
			}
		case <-time.After(100 * time.Microsecond):
		//default:
			//do work here			
			j += 1
			fmt.Println(j)
			break

		}
	}
	//fmt.Println("exit work loop")
}

func check_input(msg chan string) {
	reader := bufio.NewReader(os.Stdin)
	for {
		line, err := reader.ReadString('\n')

		if err != nil {
			// You may check here if err == io.EOF
			break
		}

		if strings.TrimSpace(line) == "t" {
			msg <- "terminate"
		}
	}
}
英文:

I run a goroutine to increment a counter, which can be interrupted by command line input "t\n"

In the select statement, if I choose to use default:, the counter variable j flies forword. That seems normal to me.

However, if I choose to use case &lt;-time.After(100*time.Microsecond):, the counter j only adds up to 60 or so in one second, instead of 10,000.

In fact no matter what value I put in time.After(), I only get about 60Hz rate running through the select statement.

Why?

package main
import (
	&quot;bufio&quot;
	&quot;fmt&quot;
	&quot;os&quot;
	&quot;strings&quot;
	&quot;time&quot;
)

func main() {
	message := make(chan string)
	go check_input(message)
	work_loop(message)
}

func work_loop(message chan string) {
	//var j [][]int
	var j int
	t0:=time.Now()
Loop:
	for {
		select {
		case msg := &lt;-message:
			if msg == &quot;terminate&quot; {
				//fmt.Println(&quot;end task&quot;)
				t1:=time.Now()
				fmt.Println(j)
				fmt.Println(&quot;total duration:&quot;, t1.Sub(t0))
				break Loop
			}
		case &lt;-time.After(100 * time.Microsecond):
		//default:
			//do work here			
			j += 1
			fmt.Println(j)
			break

		}
	}
	//fmt.Println(&quot;exit work loop&quot;)
}

func check_input(msg chan string) {
	reader := bufio.NewReader(os.Stdin)
	for {
		line, err := reader.ReadString(&#39;\n&#39;)

		if err != nil {
			// You may check here if err == io.EOF
			break
		}

		if strings.TrimSpace(line) == &quot;t&quot; {
			msg &lt;- &quot;terminate&quot;
		}
	}
}

答案1

得分: 1

这与time.Timer的精度有关。查看time.After的文档:

> [...] 它等价于NewTimer(d).C。

以及time.NewTimer的文档:

> NewTimer创建一个新的计时器,在至少持续时间d之后,将在其通道上发送当前时间。

(重点在于“至少”)

这是因为NewTimer委托给一个运行时(依赖于操作系统)计时器,使得该计时器的行为取决于底层操作系统(以及Go集成的实现)。

总的来说,根据我的经验,在任何语言中,特别是在Windows XP上,亚毫秒级的精度在跨平台支持方面并不好。

英文:

It has to do with the precision of time.Timer. Looking at the documentation of time.After:

> [...] It is equivalent to NewTimer(d).C.

and the documentation of time.NewTimer:

> NewTimer creates a new Timer that will send the current time on its channel after at least duration d.

(emphasis mine)

The reason for this is that NewTimer delegates to a runtime (OS-dependent) timer,making the behavior of this timer dependent on the underlying OS (and the implementation of the Go integration).

In general, it is my experience that sub-millisecond granularity does not have good cross-platform support in any language, especially on Windows XP.

huangapple
  • 本文由 发表于 2013年11月8日 05:59:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/19847533.html
匿名

发表评论

匿名网友

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

确定