Home > Mobile >  Why does the goroutine not block for time.Sleep(duration)
Why does the goroutine not block for time.Sleep(duration)

Time:10-23

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.

CodePudding user response:

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"`)
}

CodePudding user response:

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)
    }
}

  • Related