> But is it not guaranteed that runtime.Gosched() will at least check if 
another goroutine is runnable?

It checks, but I believe that at the time that it checks there are often no 
other runnable goroutines. The execution tracer will give you the answer to 
this.

On Wednesday, 4 April 2018 04:12:40 UTC+10, brianbl...@gmail.com wrote:
>
> 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 < 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.

Reply via email to