A printf, especially the first one in the program is likely to cause the goroutine going off to the write(2) syscall to block long enough that a new thread is created to replace it. Once the original thread comes back from the syscall it will find that it has nothing to do, as you set runtime Gomaxprocs to one and will be parked by the scheduler.
What your program is doing is sending a bunch of work on an _non blocking_ channel then printing the difference between the start time and the end time (btw, use t0 := time.Now(); time.Since(t0)) There is nothing in the doWork goroutine that prevents the main goroutine from exiting, so as soon as the scheduler is perturbed enough to schedule the main goroutine, your program will exit. The take away: runtime.Gosched is _not_ guarenteed to transfer control to a runnable goroutine, because it is not defined if a send, c <- 0, will transfer control to the receiving goroutine or not. If you're lucky then 1000 sends will happen without transferring control to doWork. If you are not then control is transferred at some point in that 1000, and because you told the sending goroutine to sleep for 1 millisecond between sends, when you call runtime.Gosched in doWork, the main goroutine was asleep (therefore not runnable) so there is nothign to schedule; so you waste another 100ms, then try again to reschedule. Ps. The Go execution tracer will show you what is happening with your program. I recommend using it to get a greater understanding of your programs behaviour. On Tuesday, 3 April 2018 14:56:49 UTC+10, brianbl...@gmail.com wrote: > > I've run into some mysterious behavior, where Gosched() works as expected > in Mac OS X, but only works as expected in Ubuntu if I put a logging > statement before it. > > I originally posted this on Stack Overflow but was directed here. Post: > https://stackoverflow.com/questions/49617451/golang-scheduler-mystery-linux-vs-mac-os-x > > Any help would be greatly appreciated! Very curious what's going on here, > as this behavior came up while I was trying to write a websocket broadcast > server. Here's a minimal setup that reproduces the behavior: > > The main goroutine sleeps for 1000 periods of 1ms, and after each sleep > pushes a dummy message onto another goroutine via a channel. The second > goroutine listens for new messages, and every time it gets one it does 10ms > of work. So without any runtime.Gosched() calls, the program will take 10 > seconds to run. > > When I add periodic runtime.Gosched() calls in the second goroutine, as > expected the program runtime shrinks down to 1 second on my Mac. However, > when I try running the same program on Ubuntu, it still takes 10 seconds. I > made sure to set runtime.GOMAXPROCS(1) in both cases. > > Here's where it gets really strange: if I just add a logging statement > before the the runtime.Gosched() calls, then suddenly the program runs in > the expected 1 second on Ubuntu as well. > > > package main > import ( > "time" > "log" > "runtime") > > func doWork(c chan int) { > for { > <-c > > // This outer loop will take ~10ms. > for j := 0; j < 100 ; j++ { > // The following block of CPU work takes ~100 microseconds > for i := 0; i < 300000; i++ { > _ = i * 17 > } > // Somehow this print statement saves the day in Ubuntu > log.Printf("donkey") > runtime.Gosched() > } > }} > > func main() { > runtime.GOMAXPROCS(1) > c := make(chan int, 1000) > go doWork(c) > > start := time.Now().UnixNano() > for i := 0; i < 1000; i++ { > time.Sleep(1 * time.Millisecond) > > // Queue up 10ms of work in the other goroutine, which will backlog > // this goroutine without runtime.Gosched() calls. > c <- 0 > } > > // Whole program should take about 1 second to run if the Gosched() calls > // work, otherwise 10 seconds. > log.Printf("Finished in %f seconds.", float64(time.Now().UnixNano() - > start) / 1e9)} > > > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.