Reputation: 5245
I have a gRPC server, written in Python 3.6. This server follows the pattern described in the gRPC examples as follows:
from concurrent import futures
import logging
import grpc
import helloworld_pb2
import helloworld_pb2_grpc
class Greeter(helloworld_pb2_grpc.GreeterServicer):
def SayHello(self, request, context):
return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name)
# ...
def ReadRemoteData(self, request, context):
return fetch_some_data_io_bound()
def serve():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
server.add_insecure_port('[::]:50051')
server.start()
server.wait_for_termination()
if __name__ == '__main__':
logging.basicConfig()
serve()
In my server application, there are a lot more methods, but in general is more of the same.
There are a number of these methods that are currently a bottleneck for my server and I would like to optimize those by running them using async
(these methods spend good time waiting on IO so they are a good candidate).
The newest versions of grpc
now support async
as seen in this example, by creating an async server with server = grpc.aio.server()
.
My problem is the following:
The server has a lot of gRPC methods, many of which are very complex. I would like to avoid rewriting any method that is not currently a bottleneck and leave them as they are. I would like to rewrite only those methods that would benefit from an async implementation, which is just a small fraction of the total. I can't change the .proto
definition to split the service into async/non-async, for backwards-compatibility reasons.
The question is, is it possible to combine, somehow, async and non async methods in the same gRPC service?
Upvotes: 2
Views: 2432
Reputation: 2091
Yes, it's possible. The application needs to create the asyncio server with an extra argument which is migration_thread_pool
. This is indeed an essential feature for migration.
See documentation at https://grpc.github.io/grpc/python/grpc_asyncio.html#grpc.aio.server
import asyncio
from concurrent import futures
import logging
import grpc
import helloworld_pb2
import helloworld_pb2_grpc
class Greeter(helloworld_pb2_grpc.GreeterServicer):
def SayHello(self, request, context):
return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name)
# ...
def ReadRemoteData(self, request, context):
return fetch_some_data_io_bound()
async def serve():
server = grpc.aio.server(futures.ThreadPoolExecutor(max_workers=10))
helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
server.add_insecure_port('[::]:50051')
await server.start()
await server.wait_for_termination()
if __name__ == '__main__':
logging.basicConfig()
asyncio.run(serve())
Upvotes: 4