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 )
Related
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
When debugging a program that makes use of say context.WithTimeout when you are not stepping through lines the clock keeps ticking, so before you can debug code piece that depends on given context, that context becomes done thus the code piece you are interested in debugging does not execute. For example in the following snippet I have to increase the timestamp value to be able to step through do() and retry() because otherwise timeout will be reached way before I can do it:
package main
import (
"context"
"fmt"
"math/rand"
"time"
)
const success = 0.1
const timeframe = time.Microsecond * 2
func main() {
ctx, cancel := context.WithTimeout(context.Background(), timeframe)
do(ctx, cancel)
}
func do(ctx context.Context, cancel context.CancelFunc) {
defer retry(ctx, cancel)
select {
case <-ctx.Done(): // timeout will be reached before i reach this line
panic("fail")
default:
if rand.Float64() < success {
cancel()
fmt.Println("success")
return
} else {
fmt.Println("fail")
}
}
func retry(ctx context.Context, cancel context.CancelFunc) {
r := recover()
if r == nil {
do(ctx, cancel)
}
}
I haven't used English that much to talk about programming and tech so, feel free to ask to rephrase.
You can use the build tag trick explained in this answer.
Basically create 2 files, one to hold the normal timeout value and the other to hold a longer timeout when running under delve.
// +build delve
package main
import "time"
const Timeframe = 10 * time.Hour
// +build !delve
package main
import "time"
const Timeframe = 2 * time.Microsecond
Use --build-flags='-tags=delve' when calling delve to choose the correct file.
How to stop the time when not stepping through lines during debugging?
You simply cannot.
You either have to increase your timeouts so large that you can do your manual debugging or not use a debugger.
I am trying to run this below piece of code
package main
import (
"fmt"
"time"
)
func main() {
time.Sleep(time.Millisecond*6000)
fmt.Println("Done")
}
As one expects, it waits for 6 seconds, print "done" and then exits
But if I remove the print statement,
package main
import (
"time"
)
func main() {
time.Sleep(time.Millisecond*6000)
}
it doesn't wait and exits immediately. Why?
Consequently, look at the code below
package main
import (
"fmt"
"time"
)
func main() {
c := make(chan int)
go count(6, c)
time.Sleep(time.Millisecond*5000)
}
func count(num int, c chan int) {
for i := 1; i <= num; i++ {
fmt.Println(i)
c <- i
time.Sleep(time.Millisecond*2000)
}
close(c)
}
Here the count goroutine will get blocked trying to send i to a channel when no receiver is there to read it and the main function immediately exits even though there is a sleep statement after it. But when I remove the statement
c <- i
the count goroutine gets to count till 3 since the main function does wait for those 5 seconds as stated.
What is going on here?
Run it locally, and it will wait. The output on the Go Playground is cached. If there is no output, it doesn't make you wait 6 seconds for nothing. If there is output, the timing of the output is preserved.
Read blog post: The Go Blog: Inside the Go Playground:
We capture the timing of each write to standard output and standard error and provide it to the client. Then the client can "play back" the writes with the correct timing, so that the output appears just as if the program were running locally.
I'm going through 'A Tour of Go' and have been editing most of the lessons to make sure I fully understand them. I have a question regarding: https://tour.golang.org/concurrency/1
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")
}
Leaving main the way it is produces a random ordering of hellos and worlds because the threads are executing in different orders each time the program runs. I have two questions:
If I remove go from the line with world and add it to the line with hello, world is printed 5 times and hello is not printed at all. Why is that?
If I add go in front of both lines, nothing is printed at all. Why is that?
I have some experience with concurrency using C++ (although it was a while ago) and some more recent experience with Python, but would describe my overall experience with concurrency fairly novice-level.
Thanks!
The program terminates before you get a chance to see the results.
You can fix this by adding a statement that ensures main doesn't exit before the other routines are finished.
From Go - Concurrency:
With a goroutine we return immediately to the next line and don't wait for the function to complete.
They give a code example:
package main
import "fmt"
func f(n int) {
for i := 0; i < 10; i++ {
fmt.Println(n, ":", i)
}
}
func main() {
go f(0)
var input string
fmt.Scanln(&input)
}
In regards to the code above:
This is why the call to the Scanln function has been included; without it the program would exit before being given the opportunity to print all the numbers.
If I remove the go keyword from the line say("world") and add it to the line say("hello"), world is printed 5 times and hello is not printed at all. Why is that?
If I add the go in front of both lines, nothing is printed at all. Why is that?
In both cases the same problem occurs, you are executing unsynchronized operations. It results in your program returning from main before all started work was processed. The specification states that When that [main] function invocation returns, the program exits. It does not wait for other (non-main) goroutines to complete.
When you use the go keyword, the runtime starts the execution of a function call as an independent concurrent thread of control. You need to use the synchronization language primitives to re synchronize the exit order of operations following the call to main with the remaining asynchronous jobs.
The language offers channels or otherwise WaitGroups via the sync package to help you implement that behavior.
For example
package main
import (
"fmt"
"time"
"sync"
)
var wg sync.WaitGroup
func say(s string) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
wg.Done()
}
}
func main() {
wg.Add(5)
say("world")
wg.Add(5)
say("hello")
wg.Wait()
}
I've a long running server written in Go. Main fires off several goroutines where the logic of the program executes. After that main does nothing useful. Once main exits, the program will quit. The method I am using right now to keep the program running is just a simple call to fmt.Scanln(). I'd like to know how others keep main from exiting. Below is a basic example. What ideas or best practices could be used here?
I considered creating a channel and delaying exit of main by receiving on said channel, but I think that could be problematic if all my goroutines become inactive at some point.
Side note: In my server (not the example), the program isn't actually running connected to a shell, so it doesn't really make sense to interact with the console anyway. For now it works, but I'm looking for the "correct" way, assuming there is one.
package main
import (
"fmt"
"time"
)
func main() {
go forever()
//Keep this goroutine from exiting
//so that the program doesn't end.
//This is the focus of my question.
fmt.Scanln()
}
func forever() {
for ; ; {
//An example goroutine that might run
//indefinitely. In actual implementation
//it might block on a chanel receive instead
//of time.Sleep for example.
fmt.Printf("%v+\n", time.Now())
time.Sleep(time.Second)
}
}
Block forever. For example,
package main
import (
"fmt"
"time"
)
func main() {
go forever()
select {} // block forever
}
func forever() {
for {
fmt.Printf("%v+\n", time.Now())
time.Sleep(time.Second)
}
}
The current design of Go's runtime assumes that the programmer is responsible for detecting when to terminate a goroutine and when to terminate the program. The programmer needs to compute the termination condition for goroutines and also for the entire program. A program can be terminated in a normal way by calling os.Exit or by returning from the main() function.
Creating a channel and delaying exit of main() by immediately receiving on said channel is a valid approach of preventing main from exiting. But it does not solve the problem of detecting when to terminate the program.
If the number of goroutines cannot be computed before the main() function enters the wait-for-all-goroutines-to-terminate loop, you need to be sending deltas so that main function can keep track of how many goroutines are in flight:
// Receives the change in the number of goroutines
var goroutineDelta = make(chan int)
func main() {
go forever()
numGoroutines := 0
for diff := range goroutineDelta {
numGoroutines += diff
if numGoroutines == 0 { os.Exit(0) }
}
}
// Conceptual code
func forever() {
for {
if needToCreateANewGoroutine {
// Make sure to do this before "go f()", not within f()
goroutineDelta <- +1
go f()
}
}
}
func f() {
// When the termination condition for this goroutine is detected, do:
goroutineDelta <- -1
}
An alternative approach is to replace the channel with sync.WaitGroup. A drawback of this approach is that wg.Add(int) needs to be called before calling wg.Wait(), so it is necessary to create at least 1 goroutine in main() while subsequent goroutines can be created in any part of the program:
var wg sync.WaitGroup
func main() {
// Create at least 1 goroutine
wg.Add(1)
go f()
go forever()
wg.Wait()
}
// Conceptual code
func forever() {
for {
if needToCreateANewGoroutine {
wg.Add(1)
go f()
}
}
}
func f() {
// When the termination condition for this goroutine is detected, do:
wg.Done()
}
Go's runtime package has a function called runtime.Goexit that will do exactly what you want.
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.
Example in the playground
package main
import (
"fmt"
"runtime"
"time"
)
func main() {
go func() {
time.Sleep(time.Second)
fmt.Println("Go 1")
}()
go func() {
time.Sleep(time.Second * 2)
fmt.Println("Go 2")
}()
runtime.Goexit()
fmt.Println("Exit")
}
Nobody mentioned signal.Notify(c chan<- os.Signal, sig ...os.Signal)
Example:
package main
import (
"fmt"
"time"
"os"
"os/signal"
"syscall"
)
func main() {
go forever()
quitChannel := make(chan os.Signal, 1)
signal.Notify(quitChannel, syscall.SIGINT, syscall.SIGTERM)
<-quitChannel
//time for cleanup before exit
fmt.Println("Adios!")
}
func forever() {
for {
fmt.Printf("%v+\n", time.Now())
time.Sleep(time.Second)
}
}
Here is a simple block forever using channels
package main
import (
"fmt"
"time"
)
func main() {
done := make(chan bool)
go forever()
<-done // Block forever
}
func forever() {
for {
fmt.Printf("%v+\n", time.Now())
time.Sleep(time.Second)
}
}
You could daemonize the process using Supervisor (http://supervisord.org/). Your function forever would just be a process that it runs, and it would handle the part of your function main. You would use the supervisor control interface to start/shutdown/check on your process.