// https://github.com/AsynkronIT/protoactor-go // https://pkg.go.dev/github.com/AsynkronIT/protoactor-go/actor package main import ( "os"; "strconv"; "fmt"; "time"; "runtime"; "sync/atomic" "github.com/asynkron/protoactor-go/actor" ) var Messages, Times uint64 = 100_000, 10 var Processors int = 4 var starttime time.Time; var shake = make( chan string ) var actorCnt uint64 = 0 type IntMsg struct { val int } type CharMsg struct { val rune } type StateMsg struct {} var statemsg StateMsg type Client struct { servers [] * actor.PID; intmsg [] IntMsg; charmsg [] CharMsg; results, times uint64; } type Server struct {} var system * actor.ActorSystem var client * actor.PID func ( state * Server ) Receive( context actor.Context ) { switch msg := context.Message().(type) { case * IntMsg: msg.val = 7 system.Root.Send( client, msg ) case * CharMsg: msg.val = 'x' system.Root.Send( client, msg ) case * StateMsg: if ( atomic.AddUint64( &actorCnt, 1 ) == Messages + 1 ) { shake <- "hand" } // if default: // ignore actor.Started message } } func process( state * Client, context * actor.Context ) { state.results++ if ( state.results == 2 * Messages ) { state.times += 1 if ( state.times == Times ) { for i := uint64(0); i < Messages; i += 1 { system.Root.Send( state.servers[i], &statemsg ) } if ( atomic.AddUint64( &actorCnt, 1 ) == Messages + 1 ) { shake <- "hand" } // if return } state.results = 0 system.Root.Send( (*context).Self(), &statemsg ) } } func ( state * Client ) Receive( context actor.Context ) { switch context.Message().(type) { case * IntMsg: process( state, &context ) case * CharMsg: process( state, &context ) case * StateMsg: for i := uint64(0); i < Messages; i += 1 { system.Root.Send( state.servers[i], &state.intmsg[i] ) system.Root.Send( state.servers[i], &state.charmsg[i] ) } default: // ignore actor.Started message } } func usage() { fmt.Printf( "Usage: %v " + "[ messages (> 0) | 'd' (default %v) ] " + "[ processors (> 0) | 'd' (default %v) ] " + "[ Times (> 0) | 'd' (default %v) ]\n", os.Args[0], Messages, Processors, Times ); os.Exit( 1 ); } func main() { switch len( os.Args ) { case 4: if os.Args[3] != "d" { // default ? Times, _ = strconv.ParseUint( os.Args[3], 10, 64 ) if Times < 1 { usage(); } } // if fallthrough case 3: if os.Args[2] != "d" { // default ? Processors, _ = strconv.Atoi( os.Args[2] ) if Processors < 1 { usage(); } } // if fallthrough case 2: if os.Args[1] != "d" { // default ? Messages, _ = strconv.ParseUint( os.Args[1], 10, 64 ) if Messages < 1 { usage(); } } // if case 1: // use defaults default: usage(); } // switch runtime.GOMAXPROCS( Processors ); starttime = time.Now(); system = actor.NewActorSystem(); servers := make( [] * actor.PID, Messages ); intmsg := make( []IntMsg, Messages ); charmsg := make( []CharMsg, Messages ); props := actor.PropsFromProducer( func() actor.Actor { return &Client{ servers, intmsg, charmsg, 0, 0 } }) client = system.Root.Spawn(props) for r := uint64(0); r < Messages; r += 1 { // create messages and actors props := actor.PropsFromProducer( func() actor.Actor { return &Server{} }) servers[r] = system.Root.Spawn(props) } // for system.Root.Send( client, &statemsg ); <- shake // wait for actors to finish fmt.Printf( "%.2f\n", time.Since( starttime ).Seconds() ); } // main // /usr/bin/time -f "%Uu %Ss %Er %Mkb" GoMatrix // Local Variables: // // tab-width: 4 // // compile-command: "go build" // // End: //