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  }