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.

Reply via email to