Golang设置10秒超时的方法与问题排查
Golang设置10秒超时的方法与问题排查
你好,我正在编写一个程序,程序会询问用户“是否要继续?”。如果用户输入“是”,则程序继续运行;如果用户在10秒内没有输入任何内容,则程序将退出。我们使用Scanf读取输入,是否有办法实现这个功能?
上述代码在 answer 变量上创建了一个竞态条件,因为一个协程在 fmt.Scanln(..) 处写入 answer,而另一个协程在 if answer == "" { .. } 处读取 answer。
更多关于Golang设置10秒超时的方法与问题排查的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
哟, 你需要使用 go-func 语句。 它会为你的函数启动一个新的 goroutine。就像这样:
var answer string = ""
go func() {
time.Sleep(10 * time.Second)
if answer == "" {
fmt.Println("timeout")
os.Exit(0)
}
}()
fmt.Scanln(&answer)
fmt.Println("answer is " + answer)
或许可以像这样:
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
result := make(chan string)
go func() {
var answer string
fmt.Scanln(&answer)
result <- answer
}()
select {
case r := <-result:
fmt.Println("answer is:", r)
case <-ctx.Done():
fmt.Println("timeout")
}
}
这不就是 <-time.After(duration) 的用途吗?
package main
import (
"fmt"
"time"
)
func main() {
result := make(chan string)
go func() {
var answer string
fmt.Scanln(&answer)
result <- answer
}()
select {
case <-time.After(10 * time.Second):
fmt.Println("timeout")
case r := <-result:
fmt.Println("answer is:", r)
}
}
我没有发现 go run -race 返回任何问题,但如果有的话,我们或许可以在这里使用互斥锁,所以:
package main
import (
"fmt"
"os"
"sync"
"time"
)
func main() {
m := &sync.Mutex{}
var answer string = ""
fmt.Print("do you want to continue?: ")
go func() {
time.Sleep(10 * time.Second)
m.Lock()
isEmpty := answer == ""
m.Unlock()
if isEmpty {
fmt.Println("timeout")
os.Exit(0)
}
}()
fmt.Scanln(&answer)
fmt.Println("answer is " + answer)
}
互斥锁也必须包裹住 fmt.Scanln(&answer) —— 但这并不是一个好主意,因为 fmt.Scanln 会阻塞更长时间,从而也会阻塞互斥锁。
除此之外,没有办法取消 fmt.Scanln 调用,因为它从 os.Stdin 读取。所以,即使你得到了超时(例如在另一个 goroutine 中使用 time.Sleep),也没有函数可以停止 fmt.Scanln。
为了解决这个问题,不要直接在 os.Stdin 上使用 Scanln,而是以一种更非阻塞的方式从 os.Stdin 读取:
package main
import (
"fmt"
"time"
"bufio"
"os"
)
func main() {
stdin := make(chan string)
go func() {
reader := bufio.NewReader(os.Stdin)
// read Stdin line by line
for {
line, _ := reader.ReadString('\n')
stdin <- line
}
}()
select {
case line := <-stdin:
fmt.Println("Your input:", line)
// use fmt.Scanf(line, ...) now
case <-time.After(10 * time.Second):
fmt.Println("Timeout.")
}
}


