英文:
Why does the goroutine not block for time.Sleep(duration)
问题
我运行的程序:
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("开始时间:", startTime)
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt)
// 直到接收到信号为止阻塞程序。
flag.Parse()
timeToSleep, err := time.ParseDuration(sleepSeconds)
if err != nil {
fmt.Println("无法解析持续时间:", err)
return
}
fmt.Println("睡眠时间:", timeToSleep)
myChan := make(chan string)
go one(myChan)
go two(myChan)
go three(myChan)
var s os.Signal
fmt.Println("信号是:", s)
go func() {
s = <-c
fmt.Println("接收到信号后的信号是:", s)
}()
i := 0
for {
i++
generatedString := fmt.Sprintf("%d", i)
fmt.Println("生成中... ", generatedString)
myChan <- generatedString
// time.Sleep(timeToSleep)
fmt.Println("通道长度:", len(myChan))
if s != nil {
break
}
}
fmt.Println("程序运行的总时间:", time.Since(startTime))
}
func one(dataCh chan string) {
for val := range dataCh {
fmt.Printf("在函数 one 中接收到的值:%s\n", val)
time.Sleep(timeToSleep)
}
}
func two(dataCh chan string) {
for val := range dataCh {
fmt.Printf("在函数 two 中接收到的值:%s\n", val)
time.Sleep(timeToSleep)
}
}
func three(dataCh chan string) {
for val := range dataCh {
fmt.Printf("在函数 three 中接收到的值:%s\n", val)
time.Sleep(timeToSleep)
}
}
当我使用以下标志运行此程序(5秒):
./ichan -sleep "5s" > data.txt
输出令人困惑,因为我看到程序只运行了 2.31606525s
,但是所有 3 个 goroutine 应该至少被阻塞 5 秒钟。
data.txt 是此存储库的一部分,供参考,代码也在同一存储库中可用。
我的问题是: 函数 one
、two
和 three
中的 time.Sleep() 应该被阻塞,直到睡眠时间结束,然后从通道中消耗字符串,但观察结果是睡眠对 goroutine 没有任何影响。
英文:
The program that I ran:
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)
}
}
When I run this program with the following flags(5s)
./ichan -sleep "5s" > data.txt
output is puzzling as I see the program has only run for 2.31606525s
but all 3 goroutines are supposed to be blocked at least for 5 seconds each.
data.txt is part of this repository for reference, code is also available in the same repository.
My Question is: time.Sleep() in the functions one
, two
and three
are supposed to be blocked until the duration of sleep and then consume the strings from the channel, but the observation is that sleep is not having any effect on the goroutines.
答案1
得分: 2
timeToSleep, err :=
创建了一个新的局部变量 timeToSleep
,它与同名的包级变量是独立的,所以包级变量始终为零。
看起来你可能忽略了存在一个本地的持续时间标志类型:https://pkg.go.dev/flag#DurationVar
func init() {
flag.DurationVar(&timeToSleep, "sleep", 1*time.Second, `-sleep "3s"`)
}
英文:
timeToSleep, err :=
creates a new, local variable named timeToSleep that is independent of the package level variable with the same name, so the package level variable is always zero.
It seems you have missed that there is a native duration flag type: https://pkg.go.dev/flag#DurationVar
func init() {
flag.DurationVar(&timeToSleep, "sleep", 1*time.Second, `-sleep "3s"`)
}
答案2
得分: 0
相同程序的工作副本
package main
import (
"flag"
"fmt"
"os"
"os/signal"
"time"
)
var sleepSeconds string
var timeToSleep time.Duration
var err error
func init() {
flag.StringVar(&sleepSeconds, "sleep", "1s", "-sleep \"3s\"")
}
func main() {
startTime := time.Now()
fmt.Println("开始时间:", startTime)
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt)
// 阻塞直到接收到信号。
flag.Parse()
timeToSleep, err = time.ParseDuration(sleepSeconds)
if err != nil {
fmt.Println("无法解析持续时间:", err)
return
}
fmt.Println("睡眠时间:", timeToSleep)
myChan := make(chan string)
go one(myChan)
go two(myChan)
go three(myChan)
var s os.Signal
fmt.Println("信号是:", s)
go func() {
s = <-c
fmt.Println("接收到信号后的信号是:", s)
}()
i := 0
for {
i++
generatedString := fmt.Sprintf("%d", i)
fmt.Println("生成中... ", generatedString)
myChan <- generatedString
// time.Sleep(timeToSleep)
fmt.Println("通道长度:", len(myChan))
if s != nil {
break
}
}
fmt.Println("程序运行的总时间:", time.Since(startTime))
}
func one(dataCh chan string) {
for val := range dataCh {
fmt.Printf("在函数 one 中接收到的值:%s\n", val)
time.Sleep(timeToSleep)
}
}
func two(dataCh chan string) {
for val := range dataCh {
fmt.Printf("在函数 two 中接收到的值:%s\n", val)
time.Sleep(timeToSleep)
}
}
func three(dataCh chan string) {
for val := range dataCh {
fmt.Printf("在函数 three 中接收到的值:%s\n", val)
time.Sleep(timeToSleep)
}
}
英文:
Working Copy of the same program
package main
import (
"flag"
"fmt"
"os"
"os/signal"
"time"
)
var sleepSeconds string
var timeToSleep time.Duration
var err error
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)
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论