asio-grpc v3.4.0
Asynchronous gRPC with Asio/unified executors
|
This article describes how to interoperate between a GrpcContext and an asio::io_context.
Since a GrpcContext is also an asio::execution_context it supports Asio's Service mechanism. The following code will therefore implicitly create an io_context, a background thread, run the io_context on that thread and post the completion of async_wait
onto the GrpcContext where the lambda is being invoked.
Signal_set is just used as an example, it could be any Asio I/O object like ip::tcp::socket
.
While this is the most convenient approach is also has some downsides:
GrpcContext and io_context can also be created directly and used as usual: submit work and run. It is often convenient to utilize one of them as the "main" context. For an example, a gRPC server might use the io_context only for HTTP client operations and the GrpcContext for everything else.
In the following example the io_context is used as the "main" context. When its main coroutine runs to completion, it will signal the GrpcContext to stop (by releasing the work guard):
For running the contexts there are two choices:
Run on separate threads
Run on same thread
Until the GrpcContext stops:
Or until both contexts stop:
Both approaches come with their own different kind of overheads. Running on two threads might require additional synchronization in the user code while running on the same thread reduces peak performance. In the Performance section of the README you can find results for using an idle io_context with a busy GrpcContext running on the same thread (look for cpp_asio_grpc_io_context_coro
).
Event loops like the ones used in Asio and gRPC typically utilize system APIs (epoll, IOCompletionPorts, kqueue, ...) in the following order:
poll
) to sleep on ALL descriptors until one or more are ready (e.g. received data).The important part is to wait on ALL descriptors at once. Which means, for Asio and gRPC to interoperate nicely we would need to collect the descriptors first and then perform the system call to wait. However, file descriptors are created deep in the implementation details of those libraries and the sleep is performed even deeper. GRPC is working on an EventEngine which should make it possible to use Asio sockets for gRPC. Whether it will be enough to fully use Asio for all gRPC network operations remains to be seen.