For what it is worth, when I run your new code (without channels) on 
windows it takes consistently 1 second. On Linux it takes variably between 
400ms and 1.5 seconds. Both running go 1.10. But, on my systems, this seems 
to be actually measuring time.Sleep(). Removing the call to spin() and the 
second runtime.Gosched() results in the same times:

package main

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

func main() {
    runtime.GOMAXPROCS(1)

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

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

I can not speak for your original example, but in this one I would be 
looking to time.Sleep(). 

- Jake


On Tuesday, April 3, 2018 at 2:12:40 PM UTC-4, 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