[go-nuts] Re: Scheduler discrepancy between Linux and OS X with Gosched()

2018-04-03 Thread brianblakewong
Hi Dave, thanks for the reply!

It makes sense that the send c <- 0 is not guaranteed to transfer control 
to the receiving goroutine. But is it not guaranteed that runtime.Gosched() 
will at least check if another goroutine is runnable? I thought that was 
roughly the point of runtime.Gosched(). 

I see what you're saying in that when the second goroutine calls Gosched, 
the sleep period may not be finished. But this will only waste another 100 
microseconds by design (not 100 milliseconds), so it seems like control 
flow should return to the main goroutine approximately when the sleep call 
finishes.

I created a simpler example, that doesn't use channels and avoids the work 
length ambiguity, posted below. Now the secondary goroutine just does an 
infinite loop of runtime.Gosched(). It should be instantaneous to run (and 
is on my Mac), but it takes almost exactly 5 seconds on Ubuntu, suggesting 
that there is some fixed 5 millisecond delay on Gosched(). And adding a 
print above spin's Gosched makes it instantaneous.

Thanks for your patience! I'm working on an application where the ~5ms 
Gosched delay is meaningful and I am very curious to figure out what's 
going on here. 
package main

import (
"log"
"runtime"
"time"
)

func spin() {
for {
runtime.Gosched()
}
}

func main() {
runtime.GOMAXPROCS(1)
go spin()

t0 := time.Now()
for i := 0; i < 1000; i++ {
time.Sleep(10 * time.Microsecond)

runtime.Gosched()
}

log.Printf("Finished in %v.", time.Since(t0))
}


On Tuesday, April 3, 2018 at 12:56:49 AM UTC-4, 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 < 30; 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.


[go-nuts] Scheduler discrepancy between Linux and OS X with Gosched()

2018-04-02 Thread brianblakewong
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 < 30; 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.