英文:
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 <-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 (
"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"
}
}
}
答案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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论