【发布时间】:2021-12-09 15:32:11
【问题描述】:
我运行的程序:
package main
import (
"flag"
"fmt"
"os"
"os/signal"
"time"
)
var sleepSeconds string
var timeToSleep time.Duration
func init() {
flag.StringVar(&sleepSeconds, "sleep", "1s", "-sleep \"3s\"")
}
func main() {
startTime := time.Now()
fmt.Println("Start Time: ", startTime)
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt)
// Block until a signal is received.
flag.Parse()
timeToSleep, err := time.ParseDuration(sleepSeconds)
if err != nil {
fmt.Println("unable to parse the duration: ", err)
return
}
fmt.Println("Time to Sleep: ", timeToSleep)
myChan := make(chan string)
go one(myChan)
go two(myChan)
go three(myChan)
var s os.Signal
fmt.Println("Signal is, ", s)
go func() {
s = <-c
fmt.Println("After receiving Signal is, ", s)
}()
i := 0
for {
i++
generatedString := fmt.Sprintf("%d", i)
fmt.Println("Generating... ", generatedString)
myChan <- generatedString
// time.Sleep(timeToSleep)
fmt.Println("Length of Channel: ", len(myChan))
if s != nil {
break
}
}
fmt.Println("Total time the program ran for: ", time.Since(startTime))
}
func one(dataCh chan string) {
for val := range dataCh {
fmt.Printf("Value received in func one: %s\n", val)
time.Sleep(timeToSleep)
}
}
func two(dataCh chan string) {
for val := range dataCh {
fmt.Printf("Value received in func two: %s\n", val)
time.Sleep(timeToSleep)
}
}
func three(dataCh chan string) {
for val := range dataCh {
fmt.Printf("Value received in func three: %s\n", val)
time.Sleep(timeToSleep)
}
}
当我使用以下标志 (5s) 运行此程序时
./ichan -sleep "5s" > data.txt
输出令人费解,因为我看到程序只运行了2.31606525s,但所有 3 个 goroutine 都应该被阻止至少 5 秒。
data.txt 是这个repository 的一部分供参考,代码也可以在同一个存储库中找到。
我的问题是:one、two 和 three 函数中的 time.Sleep() 应该被阻塞直到睡眠持续时间,然后消耗来自channel,但观察结果是 sleep 对 goroutine 没有任何影响。
【问题讨论】:
-
您在没有同步的情况下从多个 goroutine(一个写入它)访问
s变量:这是一个数据竞争,因此是未定义的行为。 -
@icza 即使没有
s,行为也是一样的 -
如果相同,请提供一个没有数据竞争的示例,以便我们专注于真正的问题。
-
你怎么知道函数中的time.Sleep()没有阻塞效果?你观察到了什么?
-
请检查存储库中的 data.txt 文件。如果睡眠有效,则不应使用此值打印
Value received in func two: 181191,它应该是小得多的数字。但是,根据@icza 请求,我对源代码进行了更改,并使用新分支no_signals_final更新了存储库注意:我看到了相同的行为