Infinite looping with vs without time.Sleep()

Issue

I’ve got a goroutine that’s playing some audio infinitely play(). In order to keep the play() alive, I’ve got the calling function running an infinite for loop afterward.

The unexpected thing is that a barebones loop does not seem to let the function play infinitely and I’m at a loss as to why. However, if I add a simple time.Sleep(time.Second) into the body of the for-loop, it runs seemingly infinitely. Any idea as to why?

To visualize:

func PlaysForAFewSeconds() {
    go play()
    for {
    }
}

^plays for a few seconds but never breaks out

func PlaysForever() {
    go play()
    for {
        time.Sleep(time.Second)
    }
}

^ plays forever.

I’m guessing that this has something to do with how play() is implemented but I’m hoping this is a common enough problem that someone recognizes this symptom.
Thanks.

Solution

The assembly that for { } generates is jmp self, where self is the location of the jmp instruction. In other words, the CPU will just keep running jmp instructions as fast as it can. The CPU can run n instructions per second, and it doesn’t matter if this is a useless jmp or an actually useful instruction.

This is known as a “busy wait” or “spin lock”, and this behaviour is not specific to Go. Most (all?) programming languages behave like this.

There are some uses for such loops, but in Go they can often be replaced with channels:

// Simulate a function that takes 1s to complete.
func play(ch chan struct{}) {
    fmt.Println("play")
    time.Sleep(1 * time.Second)
    ch <- struct{}{}
}

func PlaysForAFewSeconds() {
    wait := make(chan struct{})
    go play(wait)
    <-wait
}

func PlaysForever() {
    wait := make(chan struct{})
    for {
        go play(wait)
        <-wait
    }
}

Reading from a channel (<-wait) is blocking and doesn’t use any CPU. I used an empty anonymous struct, which looks a bit ugly, as that doesn’t allocate any memory.

Answered By – Martin Tournoij

Answer Checked By – Pedro (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.