Goroutine Output in Windows not finish like in Linux - go

I don't understand why Goroutine in Windows didn't finish properly like Goroutine in Linux?
I already run the code in Powershell, VSCode, Goland, and even CMD, but the code never finish properly like Linux output.
below is the code:
import (
"fmt"
"time"
)
func count() {
for i := 0; i < 5; i++ {
fmt.Println(i)
time.Sleep(time.Millisecond * 1)
}
}
func main() {
go count()
time.Sleep(time.Millisecond * 2)
fmt.Println("Hello World")
time.Sleep(time.Millisecond * 5)
}
Windows Output:
0
1
Hello World
Linux Output (Which is expected output):
0
1
2
Hello World
3
4
Kindly help me understand or how to fix this.
p/s: I just started learning Go.

You seem to be trying to use time.Sleep to synchronize your go routines - in other words, so that main doesn't end before count.
This is the wrong way to synchronize goroutines. Keep in mind that most general purpose operating systems such as Linux and Windows do not guarantee timing; you need a real-time OS for that. So while you might usually get lucky and have the goroutines execute in the expected order, there is no guarantee that sleeps will make things happen in the expected order even on linux. The timing between these goroutines is simply not deterministic.
One of the correct ways to synchronize goroutines is with a sync.WaitGroup.
The following code works with or without the sleeps.
package main
import (
"fmt"
"sync"
)
func count(wg *sync.WaitGroup) {
defer wg.Done()
for i := 0; i < 5; i++ {
fmt.Println(i)
}
}
func main() {
var wg sync.WaitGroup
wg.Add(1)
go count(&wg)
fmt.Println("Hello World")
wg.Wait()
}
syc.WaitGroup is a convenient way to make sure the all goroutines are complete, in this case before the main function exits thus ending the program.
You could also do it with a channel:
package main
import (
"fmt"
)
func count(done chan bool) {
for i := 0; i < 5; i++ {
fmt.Println(i)
}
done <- true
}
func main() {
var done = make(chan bool)
go count(done)
fmt.Println("Hello World")
<-done
}

It is a well-known issue: starting from Go 1.16 time.Sleep in MS Windows uses low resolution timer, as bad as 1/64 second. Sleeping for 1 ms in Windows is anything between 1 and 16 ms.
Try printing microsecond timestamps:
package main
import (
"fmt"
"time"
)
func count() {
fmt.Println(time.Now().Nanosecond() / 1000)
for i := 0; i < 5; i++ {
fmt.Println(i, time.Now().Nanosecond()/1000)
time.Sleep(time.Millisecond * 1)
}
}
func main() {
// if runtime.GOOS == "windows" {
// initTimer()
// }
ts := time.Now().UnixNano()
fmt.Println("Main started: ", ts, (ts%1_000_000_000)/1000)
go count()
time.Sleep(time.Millisecond * 2)
fmt.Println("Hello World", time.Now().Nanosecond()/1000)
time.Sleep(time.Millisecond * 5)
fmt.Println("Main done", time.Now().Nanosecond()/1000)
}
On my Windows 10:
Main started: 1663345297398120000 398120
398703
0 398703
Hello World 405757
1 405757
2 421481
Main done 421481
The numbers are microseconds. See, how big are the intervals.
To improve timer resolution you can call timeBeginPeriod function.
//go:build windows
// +build windows
package main
import "syscall"
func initTimer() {
winmmDLL := syscall.NewLazyDLL("winmm.dll")
procTimeBeginPeriod := winmmDLL.NewProc("timeBeginPeriod")
procTimeBeginPeriod.Call(uintptr(1))
}
Calling initTimer helps a lot:
Main started: 1663345544132793500 132793
132793
0 133301
Hello World 134854
1 134854
2 136403
3 137964
4 139627
Main done 140696
Still the resolution is not 1 ms, but better than 2 ms.
The full code is here: https://go.dev/play/p/LGPv74cgN_h
Discussion thread in Golang issues: https://github.com/golang/go/issues/44343

Related

Goroutine crashes silently [duplicate]

While SayHello() executes as expected, the goroutine prints nothing.
package main
import "fmt"
func SayHello() {
for i := 0; i < 10 ; i++ {
fmt.Print(i, " ")
}
}
func main() {
SayHello()
go SayHello()
}
When your main() function ends, your program ends as well. It does not wait for other goroutines to finish.
Quoting from the Go Language Specification: Program Execution:
Program execution begins by initializing the main package and then invoking the function main. When that function invocation returns, the program exits. It does not wait for other (non-main) goroutines to complete.
See this answer for more details.
You have to tell your main() function to wait for the SayHello() function started as a goroutine to complete. You can synchronize them with channels for example:
func SayHello(done chan int) {
for i := 0; i < 10; i++ {
fmt.Print(i, " ")
}
if done != nil {
done <- 0 // Signal that we're done
}
}
func main() {
SayHello(nil) // Passing nil: we don't want notification here
done := make(chan int)
go SayHello(done)
<-done // Wait until done signal arrives
}
Another alternative is to signal the completion by closing the channel:
func SayHello(done chan struct{}) {
for i := 0; i < 10; i++ {
fmt.Print(i, " ")
}
if done != nil {
close(done) // Signal that we're done
}
}
func main() {
SayHello(nil) // Passing nil: we don't want notification here
done := make(chan struct{})
go SayHello(done)
<-done // A receive from a closed channel returns the zero value immediately
}
Notes:
According to your edits/comments: if you want the 2 running SayHello() functions to print "mixed" numbers randomly: you have no guarantee to observe such behaviour. Again, see the aforementioned answer for more details. The Go Memory Model only guarantees that certain events happen before other events, you have no guarantee how 2 concurrent goroutines are executed.
You might experiment with it, but know that the result will not be deterministic. First you have to enable multiple active goroutines to be executed with:
runtime.GOMAXPROCS(2)
And second you have to first start SayHello() as a goroutine because your current code first executes SayHello() in the main goroutine and only once it finished starts the other one:
runtime.GOMAXPROCS(2)
done := make(chan struct{})
go SayHello(done) // FIRST START goroutine
SayHello(nil) // And then call SayHello() in the main goroutine
<-done // Wait for completion
Alternatively (to icza's answer) you can use WaitGroup from sync package and anonymous function to avoid altering original SayHello.
package main
import (
"fmt"
"sync"
)
func SayHello() {
for i := 0; i < 10; i++ {
fmt.Print(i, " ")
}
}
func main() {
SayHello()
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
SayHello()
}()
wg.Wait()
}
In order to print numbers simultaneously run each print statement in separate routine like the following
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(fnScopeI int) {
defer wg.Done()
// next two strings are here just to show routines work simultaneously
amt := time.Duration(rand.Intn(250))
time.Sleep(time.Millisecond * amt)
fmt.Print(fnScopeI, " ")
}(i)
}
wg.Wait()
}
A Go program exits when the main function returns.
One option is to use something like sync.WaitGroup to wait on the other goroutines that main has spawned before returning from main.
Another option is to call runtime.Goexit() in main. From the godoc:
Goexit terminates the goroutine that calls it. No other goroutine is affected. Goexit runs all deferred calls before terminating the goroutine. Because Goexit is not a panic, any recover calls in those deferred functions will return nil.
Calling Goexit from the main goroutine terminates that goroutine without func main returning. Since func main has not returned, the program continues execution of other goroutines. If all other goroutines exit, the program crashes.
This allows main goroutine to stop executing while the background routines continue to execute. For example:
package main
import (
"fmt"
"runtime"
"time"
)
func f() {
for i := 0; ; i++ {
fmt.Println(i)
time.Sleep(10 * time.Millisecond)
}
}
func main() {
go f()
runtime.Goexit()
}
This can be cleaner than blocking forever in the main function, especially for programs that are infinite. One downside is that if all of the goroutines of a process return or exit (including the main goroutine), Go will detect this as an error and panic:
fatal error: no goroutines (main called runtime.Goexit) - deadlock!
To avoid this, at least one goroutine must call os.Exit before it returns. Calling os.Exit(0) immediately terminates the program and indicates that it did so without error. For example:
package main
import (
"fmt"
"os"
"runtime"
"time"
)
func f() {
for i := 0; i < 10; i++ {
fmt.Println(i)
time.Sleep(10 * time.Millisecond)
}
os.Exit(0)
}
func main() {
go f()
runtime.Goexit()
}

Run threads for a certain amount of time - before being killed

How do I run 10 threads, for 30 seconds each, and then return to the program execution? For example, I want
10 threads to be spawned and ran for 30 seconds.
Then all threads killed
Then second() to run (i.e. after all threads have finished executing)
So far I have the following however, when I do this, the threads (obviously) keep executing and CPU usage remains at 100% after 30s:
func main(){
for i := 0; i < 10; i++{
go thread()
}
time.Sleep(30 * time.Second)
second()
}
func thread() {
for {
// Do stuff
}
}
You could use Golang context. Here's some of my code when I was learning it.
package main
import (
"fmt"
"log"
"time"
"golang.org/x/net/context"
)
func main() {
someHandler()
}
func someHandler() {
//Create a new context with a timeout duration of six seconds. You also get a cancel function you can call early.
//You can also have context end at a certain time, instead of a timeout
ctx, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(6))
for i := 0; i < 5; i++ {
go doStuff(ctx, i)
}
select {
case <- ctx.Done():
log.Println("Got a cancel request")
return
case <-time.After(time.Second * time.Duration(5)):
//Here I'm actually ending it earlier than the timeout with cancel().
log.Println("Timed out")
cancel()
}
}
func doStuff(ctx context.Context, num int) {
for {
select {
case <-ctx.Done():
fmt.Println("Done working")
return
default:
fmt.Println("go", num, "working")
}
time.Sleep(time.Second)
}
}
Outputs:
$ go run app.go
go 0 working
go 4 working
go 2 working
go 3 working
go 1 working
go 1 working
go 0 working
go 4 working
go 3 working
go 2 working
go 0 working
go 4 working
go 2 working
go 1 working
go 3 working
go 4 working
go 3 working
go 0 working
go 2 working
go 1 working
go 3 working
go 4 working
go 1 working
go 0 working
go 2 working
2016/10/01 23:25:23 Timed out
Use a wait group and a "done" channel to cancel running go routines and and synchronize their exits before calling second. Some really cool stuff on the topic can be read here https://blog.golang.org/pipelines.
package main
import (
"fmt"
"sync"
"time"
)
func main() {
//create a "done" channel that will be used to signal to all go routines running thread to quit
done := make(chan interface{})
//create a wait group to sync all go routines before continuing program execution
wg := new(sync.WaitGroup)
for i := 0; i < 10; i++ {
//increment waitgroup
wg.Add(1)
go thread(done, wg)
}
//zzzz...
time.Sleep(30 * time.Second)
//close the done channel
close(done)
//wait for all go routines to quit
wg.Wait()
//move on
second()
}
func thread(done chan interface{}, wg *sync.WaitGroup) {
defer wg.Done()
working := true
for working {
//use a select statement to do work until done channel is closed
select {
case <-done:
//end the loop
working = false
default:
fmt.Println("doing work...")
}
}
}
func second() {
fmt.Println("program complete")
}

GOMAXPROCS already be 2, but program still hang

I already set runtime.GOMAXPROCS(2), but this program still hang when output some numbers. I can see high cpu used by this program(more than 100%), but I can't understand why the for loop goroutine can make my program not work.
go version is 1.4.2 on linux/amd64, and my pc has 4 CPUs.
here is the code:
package main
import "fmt"
import "runtime"
import "time"
func forever() {
for {
}
}
func show() {
for number := 1; number < 999999; number++ {
time.Sleep(1000)
fmt.Println(number)
}
}
func main() {
runtime.GOMAXPROCS(2)
go show()
go forever()
for {
time.Sleep(1000)
}
}
There's no need to ever have a busy loop that does nothing except burn CPU time. Not only does it consume an entire OS thread, but goroutines are cooperatively scheduled, and it will interfere with the runtime's goroutines. For example, on Go1.5 this will usually block the stop-the-world phase of the GC, (which you can test by setting GOGC=off).
To make this program run, you could insert a scheduling point in the for loop, but it would be better to remove it altogether.
func forever() {
for {
runtime.Gosched()
}
}
From code, it looks like you want to print the number in for loop in go routine. In this case why not use channel to indicate when go routine is completed with for loop and accordingly exit the main function. Something like this
package main
import "fmt"
import "runtime"
import "time"
func show(result chan bool) {
for number := 1; number < 999999; number++ {
time.Sleep(1000)
fmt.Println(number)
}
result <- true
}
func main() {
runtime.GOMAXPROCS(2)
result := make(chan bool)
go show(result)
<- result
}
It's good to use runtime.Gosched().
But in golang, time.Duration is in Nanoseconds, so time.Sleep(1000) is nearly no sleep. mostly you consider it as milliseconds like things in Java. you can try
time.Sleep( 1000 * time.MilliSecond )

why does it seem that sleep doesn't work in goroutine

package main
import (
"fmt"
"time"
)
func main() {
c := make(chan struct{})
count := 1
go func() {
for {
fmt.Println("foo", count)
count++
time.Sleep(2)
}
c <- struct{}{}
}()
fmt.Println("Hello World!")
<-c
}
This is my code , and I found it didn't sleep 2 every loop, and printed quickly. What's the reason of it? What I searched is that sleep will make goroutine give up control of cpu and when it get the control again will it check itself is sleeping?
time.Sleep takes its Duration in nanoseconds, so to delay 2 seconds it should be;
time.Sleep(2000000000)
or, as #Ainar-G points out in the comments, the more readable;
time.Sleep(2 * time.Second)

First goroutine example, weird results

This example taken from tour.golang.org/#63
package main
import (
"fmt"
"time"
)
func say(s string) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
go say("world")
say("hello")
}
The output
hello
world
hello
world
hello
world
hello
world
hello
Why world is printed only 4 times instead of 5 ?
Edit: The answer can be quoted from golang specification:
Program execution begins by initializing the main package and then
invoking the function main. When the function main returns, the
program exits. It does not wait for other (non-main) goroutines to
complete.
When your main function ends your program ends, i.e. all goroutines are terminated.
Your main terminates before go say("world") is done. If you sleep some time at the end of main you should see the last world.
Here is how you solve that synchronization problem properly - with sync.WaitGroup
Playground link
package main
import (
"fmt"
"sync"
"time"
)
func say(s string, wg *sync.WaitGroup) {
defer wg.Done()
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
wg := new(sync.WaitGroup)
wg.Add(2)
go say("world", wg)
go say("hello", wg)
wg.Wait()
fmt.Println("All done")
}
Because the calling gorouting terminates before the second one you spawned does. This causes the second to shut down. To illustrate, modify your code slightly:
package main
import (
"fmt"
"time"
)
func say(s string) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Print(i)
fmt.Println(":"+s)
}
}
func main() {
go say("world")
say("hello")
}
Try putting in a "wait" or a sleep to the end of the main function.

Resources