Re: [go-nuts] Periodic task when time.Ticker and time.Sleep are pretty expensive
Thanks everyone for looking into this. I've raised an issue https://github.com/golang/go/issues/27707 On Monday, September 17, 2018 at 4:29:15 PM UTC+8, Dave Cheney wrote: > > I've confirmed this uses 14% on a random OS X machine. Please raise a bug, > https://golang.org/issue/new > > On Monday, 17 September 2018 14:29:44 UTC+10, Robert Engels wrote: >> >> For reference, similar code under Java consumes 2.5 % CPU. >> >> I tested the Go code under OSX, and it is roughly 10%, which seems to be >> very high. Might be because the “context switching” is performed/attributed >> to the process (since it is internal), where for other systems it is the >> system call only, and so most of the cost is attributed to system/kernel >> activity. >> >> >> >> On Sep 16, 2018, at 8:47 AM, Lei Ni wrote: >> >> import ( >> "time" >> ) >> >> func main() { >> ticker := time.NewTicker(time.Millisecond) >> defer ticker.Stop() >> for range ticker.C { >> } >> } >> >> >> -- 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.
Re: [go-nuts] Periodic task when time.Ticker and time.Sleep are pretty expensive
I've confirmed this uses 14% on a random OS X machine. Please raise a bug, https://golang.org/issue/new On Monday, 17 September 2018 14:29:44 UTC+10, Robert Engels wrote: > > For reference, similar code under Java consumes 2.5 % CPU. > > I tested the Go code under OSX, and it is roughly 10%, which seems to be > very high. Might be because the “context switching” is performed/attributed > to the process (since it is internal), where for other systems it is the > system call only, and so most of the cost is attributed to system/kernel > activity. > > > > On Sep 16, 2018, at 8:47 AM, Lei Ni > > wrote: > > import ( > "time" > ) > > func main() { > ticker := time.NewTicker(time.Millisecond) > defer ticker.Stop() > for range ticker.C { > } > } > > > -- 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.
Re: [go-nuts] Periodic task when time.Ticker and time.Sleep are pretty expensive
For reference, similar code under Java consumes 2.5 % CPU. I tested the Go code under OSX, and it is roughly 10%, which seems to be very high. Might be because the “context switching” is performed/attributed to the process (since it is internal), where for other systems it is the system call only, and so most of the cost is attributed to system/kernel activity. > On Sep 16, 2018, at 8:47 AM, Lei Ni wrote: > > import ( > "time" > ) > > func main() { > ticker := time.NewTicker(time.Millisecond) > defer ticker.Stop() > for range ticker.C { > } > } > -- 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.
Re: [go-nuts] Periodic task when time.Ticker and time.Sleep are pretty expensive
Thanks for the input Jan! When running the following exact code, I saw 20% %CPU in top as well, measured on a single socket E5-2696v4 server without any vm/container/CPU intensive task. package main import ( "time" ) func main() { ticker := time.NewTicker(time.Millisecond) defer ticker.Stop() for range ticker.C { } } The following C++ program is the one I mentioned, I saw ~1% %CPU in top - #include #include int main(int argc, char **argv, char **env) { while(true) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); } } > If you're observing 10% CPU usage, it means the scheduler does its job in about 100 microseconds. Maybe it can be improved but it does not look like suspiciously too much to me - considering what's happening behind the scenes. I saw 20% %CPU usage in top when using time.Ticker, and > 10% when using time.Sleep(). This causes two real issues - 1. users of my system keep asking me why an idle server process is still taking 20% %CPU every time when they look at top. 2. the system can't scale well when running in its simulation mode. In such simulation mode, I'd be running many instances of the same program on a multi-core machine each with a slightly different set of inputs (including many SIGKILL) for testing purposes. If each process is spending 20% %CPU by just having a ticker loop, it ends up wasting a significant portion of total CPU resources which could have been spent on more process instances for more tests. Also interesting to know the standard of your mentioned "suspiciously too much" - how much is too much? To me, it is an obvious performance issue in Go's runtime. To further illustrate the problem, I've come up with another program showing that if I move the ticker/sleep part to C and let the C code to call my periodic task in Go every 1 millisecond, the %CPU is dramatically reduced to 2-3%. I believe this is not the kind of cgo "optimization" users should be doing on their own. ticker.h -- #ifndef TEST_TICKER_H #define TEST_TICKER_H void cticker(); #endif // TEST_TICKER_H ticker.c -- #include #include "ticker.h" #include "_cgo_export.h" void cticker() { for(int i = 0; i < 3; i++) { usleep(1000); Gotask(); } } ticker.go --- package main /* #include "ticker.h" */ import "C" import ( "log" ) var ( counter uint64 = 0 ) //export Gotask func Gotask() { counter++ } func main() { C.cticker() log.Printf("Gotask called %d times", counter) } On Sunday, September 16, 2018 at 5:10:07 PM UTC+8, Jan Mercl wrote: > > On Sun, Sep 16, 2018 at 10:49 AM Lei Ni > > wrote: > func main() { > ... > for { > select { > case <-ticker.C: > // call my function here > } > } > } > > Is the above the actual code you're using for the CPU usage "benchmark"? > If so, make the loop > > for range <-ticker.C { > // call my function here > } > > instead. > > > As comparison, the same can be done in C++ with about 1% %CPU in top. > > Please show the C++ code to let others know what is meant by "the same", > thanks. My guess is that the C++ code only yields the thread to the kernel > which is indeed cheaper than rescheduling goroutines in a Go program when > one of them blocks or sleeps. If you're observing 10% CPU usage, it means > the scheduler does its job in about 100 microseconds. Maybe it can be > improved but it does not look like suspiciously too much to me - > considering what's happening behind the scenes. > > FTR, a 1 msec ticker will make something called 1000 times in a second on > a common system only when almost idle otherwise. IIRC, for example Linux > schedules threads on a 100 msec base by default. > > -- > > -j > -- 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.
Re: [go-nuts] Periodic task when time.Ticker and time.Sleep are pretty expensive
On Sun, Sep 16, 2018 at 10:49 AM Lei Ni wrote: func main() { ... for { select { case <-ticker.C: // call my function here } } } Is the above the actual code you're using for the CPU usage "benchmark"? If so, make the loop for range <-ticker.C { // call my function here } instead. > As comparison, the same can be done in C++ with about 1% %CPU in top. Please show the C++ code to let others know what is meant by "the same", thanks. My guess is that the C++ code only yields the thread to the kernel which is indeed cheaper than rescheduling goroutines in a Go program when one of them blocks or sleeps. If you're observing 10% CPU usage, it means the scheduler does its job in about 100 microseconds. Maybe it can be improved but it does not look like suspiciously too much to me - considering what's happening behind the scenes. FTR, a 1 msec ticker will make something called 1000 times in a second on a common system only when almost idle otherwise. IIRC, for example Linux schedules threads on a 100 msec base by default. -- -j -- 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] Periodic task when time.Ticker and time.Sleep are pretty expensive
Hi all, In my Go program, I need to call a function roughly every millisecond. There is no hard real time requirement, so as long as I can call that function roughly 1,000 times a second (or let's say every 0.9-1.1 millisecond) everything is fine. I found time.Ticker and time.Sleep are both pretty expensive, probably because the scheduler is doing some of its magics in the background. Is there any alternative approach that can allow me to achieve the same with much less overhead? Many thanks! The following program is consistently showing 20-25% of %CPU in top. package main import ( "time" ) func main() { ticker := time.NewTicker(time.Millisecond) defer ticker.Stop() for { select { case <-ticker.C: // call my function here } } } while the following program is showing 10-15% of %CPU in top package main import ( "time" ) func main() { for { time.Sleep(time.Millisecond) // call my function here } } As comparison, the same can be done in C++ with about 1% %CPU in top. Cheers, Lei -- 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.