github.com/qiuhoude/go-web@v0.0.0-20220223060959-ab545e78f20d/prepare/23_proto_actor/inprocessbenchmark/main.go (about) 1 package main 2 3 import ( 4 "flag" 5 "os" 6 "runtime/pprof" 7 8 "github.com/AsynkronIT/protoactor-go/actor" 9 10 "log" 11 "sync" 12 13 "runtime" 14 "time" 15 16 "github.com/AsynkronIT/protoactor-go/mailbox" 17 ) 18 19 type Msg struct { 20 Sender *actor.PID 21 } 22 type Start struct { 23 Sender *actor.PID 24 } 25 26 type pingActor struct { 27 count int 28 wgStop *sync.WaitGroup 29 messageCount int 30 batch int 31 batchSize int 32 } 33 34 func (state *pingActor) sendBatch(context actor.Context, sender *actor.PID) bool { 35 if state.messageCount == 0 { 36 return false 37 } 38 39 var m interface{} = &Msg{ 40 Sender: context.Self(), 41 } 42 43 for i := 0; i < state.batchSize; i++ { 44 context.Send(sender, m) 45 } 46 47 state.messageCount -= state.batchSize 48 state.batch = state.batchSize 49 return true 50 } 51 52 func (state *pingActor) Receive(context actor.Context) { 53 switch msg := context.Message().(type) { 54 case *Start: 55 state.sendBatch(context, msg.Sender) 56 57 case *Msg: 58 state.batch-- 59 if state.batch > 0 { 60 return 61 } 62 63 if !state.sendBatch(context, msg.Sender) { 64 state.wgStop.Done() 65 } 66 } 67 } 68 69 func newPingActor(stop *sync.WaitGroup, messageCount int, batchSize int) actor.Producer { 70 return func() actor.Actor { 71 return &pingActor{ 72 wgStop: stop, 73 messageCount: messageCount, 74 batchSize: batchSize, 75 } 76 } 77 } 78 79 var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file") 80 var blockProfile = flag.String("blockprof", "", "execute contention profiling and save results here") 81 82 func main() { 83 flag.Parse() 84 if *cpuprofile != "" { 85 f, err := os.Create(*cpuprofile) 86 if err != nil { 87 log.Fatal(err) 88 } 89 pprof.StartCPUProfile(f) 90 defer pprof.StopCPUProfile() 91 } 92 93 // Check for lock contention profiling 94 if *blockProfile != "" { 95 prof, err := os.Create(*blockProfile) 96 if err != nil { 97 log.Fatal(err) 98 } 99 runtime.SetBlockProfileRate(1) 100 defer func() { 101 pprof.Lookup("block").WriteTo(prof, 0) 102 }() 103 } 104 105 runtime.GOMAXPROCS(runtime.NumCPU()) 106 runtime.GC() 107 108 var wg sync.WaitGroup 109 110 messageCount := 1000000 111 batchSize := 100 112 tps := []int{300, 400, 500, 600, 700, 800, 900} 113 log.Println("Dispatcher Throughput Elapsed Time Messages per sec") 114 for _, tp := range tps { 115 116 d := mailbox.NewDefaultDispatcher(tp) 117 118 clientProps := actor. 119 PropsFromProducer(newPingActor(&wg, messageCount, batchSize)). 120 WithMailbox(mailbox.Bounded(batchSize + 10)). 121 WithDispatcher(d) 122 rootContext := actor.EmptyRootContext 123 124 echoProps := actor. 125 PropsFromFunc( 126 func(context actor.Context) { 127 switch msg := context.Message().(type) { 128 case *Msg: 129 context.Send(msg.Sender, msg) 130 } 131 }). 132 WithMailbox(mailbox.Bounded(batchSize + 10)). 133 WithDispatcher(d) 134 135 clients := make([]*actor.PID, 0) 136 echos := make([]*actor.PID, 0) 137 clientCount := runtime.NumCPU() * 2 138 for i := 0; i < clientCount; i++ { 139 client := rootContext.Spawn(clientProps) 140 echo := rootContext.Spawn(echoProps) 141 clients = append(clients, client) 142 echos = append(echos, echo) 143 wg.Add(1) 144 } 145 start := time.Now() 146 147 for i := 0; i < clientCount; i++ { 148 client := clients[i] 149 echo := echos[i] 150 151 rootContext.Send(client, &Start{ 152 Sender: echo, 153 }) 154 } 155 156 wg.Wait() 157 elapsed := time.Since(start) 158 x := int(float32(messageCount*2*clientCount) / (float32(elapsed) / float32(time.Second))) 159 log.Printf(" %v %s %v", tp, elapsed, x) 160 for i := 0; i < clientCount; i++ { 161 client := clients[i] 162 rootContext.StopFuture(client).Wait() 163 echo := echos[i] 164 rootContext.StopFuture(echo).Wait() 165 } 166 runtime.GC() 167 time.Sleep(2 * time.Second) 168 } 169 170 // f, err := os.Create("memprofile") 171 // if err != nil { 172 // log.Fatal(err) 173 // } 174 // pprof.WriteHeapProfile(f) 175 // f.Close() 176 }