And I had write a test case to be a proof that: *current golang's scheduler is not*
*good at cpu intensive applications* Here it is: package main import "fmt" import "runtime" //import "math/big" import "time" /* #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/time.h> #include <time.h> int deadloop() { long long ct=0; struct timespec start, stop; clock_gettime(CLOCK_MONOTONIC_RAW, &start); while (1) { ct++; if (ct%800000000==0){ clock_gettime(CLOCK_MONOTONIC_RAW, &stop); printf( "cgo-> ct:%ld | c loop delay:%lu ms\n", ct, ((stop.tv_sec - start.tv_sec) * 1000000 + (stop.tv_nsec - start.tv_nsec) / 1000)/1000); clock_gettime(CLOCK_MONOTONIC_RAW, &start); } } return rand(); } */ import "C" type callRet struct { ret int } type callIn struct { ret_chan chan *callRet arg1 int } var delta_t_ms float64 func caller(call_in_c chan *callIn, arg1 int) int { ret_c := make(chan *callRet, 1) ci := callIn{ret_c, arg1} t1 := time.Now().UnixNano() call_in_c <- &ci ret := <-ret_c t2 := time.Now().UnixNano() _, _ = t1, t2 if float64(t2-t1)/1e6 > delta_t_ms { delta_t_ms = float64(t2-t1) / 1e6 } //fmt.Println(t2, t1, float64(t2-t1)/1e6) return ret.ret } func call_srv(call_in_c chan *callIn) { //runtime.LockOSThread() ct := 0 for { select { case in := <-call_in_c: ret_c := in.ret_chan ret := callRet{3 + in.arg1} ret_c <- &ret ct++ if ct%10000 == 0 { fmt.Println("channel_op_ct:", ct, " max_channel_op_delay:", delta_t_ms, "ms") } //default: // time.Sleep(1 * time.Millisecond) } } //runtime.UnlockOSThread() } func init() { //runtime.LockOSThread() } func main() { p := fmt.Println runtime.GOMAXPROCS(2) call_in_c := make(chan *callIn, 2000) fp := func(call_in_c chan *callIn) { ct := 0 for ; ct < 10*60000; ct = ct + 1 { caller(call_in_c, 1) time.Sleep(time.Microsecond / 1000) } p("done:)") } go fp(call_in_c) //go fp(call_in_c) go func() { for { fmt.Println("heartbeat... ", "max_channel_op_delay:", delta_t_ms, "ms") time.Sleep(1000 * 1000 * time.Microsecond) } }() godeadloop := func() { ct := 0 t1 := time.Now().UnixNano() for { ct++ if ct%360000000 == 0 { t2 := time.Now().UnixNano() fmt.Println("hooray", t2, t1, float64(t2-t1)/1e6) t1 = t2 } if ct%360000000 == 0 { runtime.Gosched() } } } _ = godeadloop _ = C.deadloop go C.deadloop() //go godeadloop() // <<--------- call_srv(call_in_c) return } After go run it yields: CPU intensive code in cgo: > > heartbeat... max_channel_op_delay: 0.81509 ms > channel_op_ct: 590000 max_channel_op_delay: 0.81509 ms > channel_op_ct: 600000 max_channel_op_delay: 0.81509 ms > done:) > cgo-> ct:3200000000 | *c loop delay:1039 ms* > heartbeat... *max_channel_op_delay: 0.81509 ms* And after changing 'go C.deadloop' to 'go godeadloop()' (at the very bottom of this codes) it yields: CPU intensive code in pure go code: > > hooray 1498049095239314392 1498049094319306332 *920.00806 ms (go dead > loop)* > channel_op_ct: 600000 max_channel_op_delay: 970.921145 ms > done:) > heartbeat... *max_channel_op_delay: 970.921145 ms* > hooray 1498049096158299639 1498049095239314392 918.985247 You see! There is 0.8ms latency drops to 970ms after using cpu intensive codes in golang comparing to unload it to cgo directly. And this kinda penalty could definitely cause the unstability of go application which has some really massive things to handle in pure go codes. On Wednesday, 21 June 2017 20:49:59 UTC+8, Ronald wrote: > > This piece of code prohibits cooperative scheduling in 599 999 999 out of > > 600 000 000 times. It's a nice example how to not code in Go. > > > Thanks Jan for your reply :) > > >> Particularly, delays should be implemented using the functions in the time > > package, not by burning CPU cycles at the expense of other useful work > > that could have been done instead. > > > Sure this kinda of dead loop is just an simulation about some really CPU > intensive jobs. > And I think for those kind of job, the delay about range [20 ms- inf ms) > is quite ordinary. > Thus I think that kind of writing is acceptable :D > > On Wed, Jun 21, 2017 at 8:08 PM, Jan Mercl <0xj...@gmail.com> wrote: > >> On Wed, Jun 21, 2017 at 1:50 PM Ronald <yunthana...@gmail.com> wrote: >> >> > for { >> > ct++ >> > if ct%600000000 == 0 { >> > t2 := time.Now().UnixNano() >> > fmt.Println("hooray", t2, t1, float64(t2-t1)/1e6) >> > t1 = t2 >> > } >> > } >> >> > This piece code is not "dead spin", it is just cpu intensive. >> >> This piece of code prohibits cooperative scheduling in 599 999 999 out of >> 600 000 000 times. It's a nice example how to not code in Go. Particularly, >> delays should be implemented using the functions in the time package, not >> by burning CPU cycles at the expense of other useful work that could have >> been done instead. >> >> -- >> >> -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.