When creating a server using gRPC
, if I start the gRPC
server in the main process, it can deal with as many as requests (thousands) from clients. However, if I start the server as a goroutine, it can only handle some requests (hundreds) and after get stuck. I have tested and confirmed this with a very simple example, google.golang.org/grpc/examples/helloworld.
Is it because spawned goroutines stack size is very small (2Kbytes), and the main goroutine's much larger? What's the difference between the main goroutine and spawned goroutines?
Example link. Modified parts of the example as follows.
greeter_server/main.go
func main() {
go func() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterGreeterServer(s, &server{})
s.Serve(lis)
}()
for {
}
}
greeter_client/main.go
func main() {
// Set up a connection to the server.
for i := 0; i < 500; i++ {
conn, err := grpc.Dial(address, grpc.WithInsecure())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewGreeterClient(conn)
for i := 0; i < 500; i++ {
// Contact the server and print out its response.
name := defaultName
if len(os.Args) > 1 {
name = os.Args[1]
}
r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: name})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("%d's Greeting: %s", i, r.Message)
}
}
}
Why is a Goroutine’s stack infinite:
ref: http://dave.cheney.net/2013/06/02/why-is-a-goroutines-stack-infinite
Empty loop:
uses 100% of a CPU Core, to wait for some operation depending to the use case you may use:
-
sync.WaitGroup
like this-
select {}
like this- channels
-
time.Sleep
No, you may try these two samples to see the stack limit of goroutines are the same:
one main goroutine on The Go Playground,
try second goroutine on The Go Playground:
both outputs are the same on the Go Playground:
outputs on a PC with
8 GB
RAM: