Git Product home page Git Product logo

asio-grpc's Introduction

asio-grpc

Reliability Rating Reliability Rating vcpkg

A Executor, Networking TS and Unified Executors interface to grpc::CompletionQueue for writing asynchronous gRPC clients and servers using C++20 coroutines, Boost.Coroutines, Asio's stackless coroutines, callbacks, sender/receiver and more.

Features

Completed features:

Example

  • Server side 'hello world':

grpc::ServerBuilder builder;
std::unique_ptr<grpc::Server> server;
helloworld::Greeter::AsyncService service;
agrpc::GrpcContext grpc_context{builder.AddCompletionQueue()};
builder.AddListeningPort(host, grpc::InsecureServerCredentials());
builder.RegisterService(&service);
server = builder.BuildAndStart();

boost::asio::co_spawn(
    grpc_context,
    [&]() -> boost::asio::awaitable<void>
    {
        grpc::ServerContext server_context;
        helloworld::HelloRequest request;
        grpc::ServerAsyncResponseWriter<helloworld::HelloReply> writer{&server_context};
        co_await agrpc::request(&helloworld::Greeter::AsyncService::RequestSayHello, service, server_context,
                                request, writer);
        helloworld::HelloReply response;
        response.set_message("Hello " + request.name());
        co_await agrpc::finish(writer, response, grpc::Status::OK);
    },
    boost::asio::detached);

grpc_context.run();

snippet source | anchor

Requirements

Tested by CI:

  • gRPC 1.41.0 (older versions work as well)
  • Boost 1.78 (min. 1.74 or standalone Asio 1.17.0)
  • MSVC 19.30.30706.0 (Visual Studio 17 2022)
  • GCC 9.3.0, 10.3.0, 11.1.0
  • Clang 10.0.0, 11.0.0, 12.0.0
  • AppleClang 13.0.0.13000029
  • C++17 or C++20

For MSVC compilers the following compile definitions might need to be set:

BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT
BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT
BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT
BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT
BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT

When using standalone Asio then omit the BOOST_ prefix.

Usage

The library can be added to a CMake project using either add_subdirectory or find_package. Once set up, include the following header:

#include <agrpc/asioGrpc.hpp>
As a subdirectory

Clone the repository into a subdirectory of your CMake project. Then add it and link it to your target.

Using Boost.Asio:

find_package(Boost)
add_subdirectory(/path/to/repository/root)
target_link_libraries(your_app PUBLIC asio-grpc::asio-grpc Boost::headers)

Or using standalone Asio:

find_package(asio)
add_subdirectory(/path/to/repository/root)
target_link_libraries(your_app PUBLIC asio-grpc::asio-grpc-standalone-asio asio::asio)

Or using libunifex:

find_package(unifex)
add_subdirectory(/path/to/repository/root)
target_link_libraries(your_app PUBLIC asio-grpc::asio-grpc-unifex unifex::unifex)

As a CMake package

Clone the repository and install it.

mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=/desired/installation/directory ..
cmake --build . --target install

Locate it and link it to your target.

Using Boost.Asio:

# Make sure CMAKE_PREFIX_PATH contains /desired/installation/directory
find_package(asio-grpc)
target_link_libraries(your_app PUBLIC asio-grpc::asio-grpc)

Or using standalone Asio:

# Make sure CMAKE_PREFIX_PATH contains /desired/installation/directory
find_package(asio-grpc)
target_link_libraries(your_app PUBLIC asio-grpc::asio-grpc-standalone-asio)

Or using libunifex:

# Make sure CMAKE_PREFIX_PATH contains /desired/installation/directory
find_package(asio-grpc)
target_link_libraries(your_app PUBLIC asio-grpc::asio-grpc-unifex)

Using vcpkg

Add asio-grpc to the dependencies inside your vcpkg.json:

{
    "name": "your_app",
    "version": "0.1.0",
    "dependencies": [
        "asio-grpc",
        // To use the Boost.Asio backend add
        // "boost-asio",
        // To use the standalone Asio backend add
        // "asio",
        // To use the libunifex backend add
        // "libunifex"
    ]
}

Locate asio-grpc and link it to your target in your CMakeLists.txt:

find_package(asio-grpc)
# Using the Boost.Asio backend
target_link_libraries(your_app PUBLIC asio-grpc::asio-grpc)
# Or use the standalone Asio backend
#target_link_libraries(your_app PUBLIC asio-grpc::asio-grpc-standalone-asio)
# Or use the libunifex backend
#target_link_libraries(your_app PUBLIC asio-grpc::asio-grpc-unifex)

Available features

boost-container - Use Boost.Container instead of <memory_resource>

See selecting-library-features to learn how to select features with vcpkg.

CMake Options

ASIO_GRPC_USE_BOOST_CONTAINER - Use Boost.Container instead of <memory_resource>

ASIO_GRPC_DISABLE_AUTOLINK - Set before using find_package(asio-grpc) to prevent asio-grpcConfig.cmake from finding and setting up interface link libraries

Performance

asio-grpc is part of grpc_bench. Head over there to compare its performance against other libraries and languages.

Results from the helloworld unary RPC
Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz, Linux, Boost 1.74, gRPC 1.41.0, asio-grpc v1.3.0, jemalloc 5.2.1

Results

1 CPU server

name req/s avg. latency 90 % in 95 % in 99 % in avg. cpu avg. memory
rust_tonic_mt 47805 20.75 ms 9.08 ms 9.95 ms 563.63 ms 101.47% 30.57 MiB
rust_thruster_mt 42444 23.41 ms 10.20 ms 11.10 ms 618.14 ms 100.88% 22.4 MiB
rust_grpcio 41832 23.71 ms 25.21 ms 26.04 ms 27.40 ms 102.47% 46.52 MiB
cpp_grpc_mt 40744 24.40 ms 25.87 ms 26.45 ms 28.27 ms 101.56% 18.47 MiB
cpp_asio_grpc libunifex 40736 24.41 ms 25.90 ms 26.38 ms 28.01 ms 101.31% 20.03 MiB
cpp_asio_grpc Boost.Coroutine 40131 24.78 ms 26.40 ms 27.06 ms 28.53 ms 101.23% 21.62 MiB
cpp_asio_grpc C++20 coroutines 39301 25.31 ms 27.15 ms 27.86 ms 30.17 ms 101.56% 18.73 MiB
cpp_grpc_callback 12295 76.83 ms 103.27 ms 111.26 ms 157.36 ms 99.13% 122.13 MiB
go_grpc 7460 127.03 ms 233.60 ms 298.85 ms 476.07 ms 76.98% 31.17 MiB

2 CPU server

name req/s avg. latency 90 % in 95 % in 99 % in avg. cpu avg. memory
cpp_asio_grpc libunifex 85160 10.16 ms 18.48 ms 22.30 ms 30.35 ms 199.12% 47.49 MiB
cpp_asio_grpc Boost.Coroutine 83983 10.35 ms 18.44 ms 22.52 ms 32.10 ms 202.86% 52.52 MiB
cpp_grpc_mt 83662 10.34 ms 18.79 ms 23.12 ms 33.93 ms 200.63% 50.81 MiB
cpp_asio C++20 coroutines 83269 10.46 ms 18.90 ms 22.81 ms 30.87 ms 200.28% 46.97 MiB
cpp_grpc_callback 78264 11.21 ms 18.83 ms 23.75 ms 35.76 ms 205.3% 156.57 MiB
rust_tonic_mt 76169 12.30 ms 32.65 ms 52.59 ms 79.94 ms 199.34% 18.65 MiB
rust_thruster_mt 68978 13.68 ms 37.60 ms 58.65 ms 86.11 ms 201.22% 14.56 MiB
rust_grpcio 67483 14.26 ms 20.94 ms 23.91 ms 28.20 ms 201.54% 39.61 MiB
go_grpc 15983 54.77 ms 101.33 ms 119.37 ms 188.73 ms 196.62% 30.62 MiB

Documentation

API reference

The main workhorses of this library are the agrpc::GrpcContext and its executor_type - agrpc::GrpcExecutor.

The agrpc::GrpcContext implements asio::execution_context and can be used as an argument to Asio functions that expect an ExecutionContext like asio::spawn.

Likewise, the agrpc::GrpcExecutor models the Executor and Networking TS requirements and Scheduler and can therefore be used in places where Asio/libunifex expects an Executor or Scheduler.

The API for RPCs is modeled closely after the asynchronous, tag-based API of gRPC. As an example, the equivalent for grpc::ClientAsyncReader<helloworld::HelloReply>.Read(helloworld::HelloReply*, void*) would be agrpc::read(grpc::ClientAsyncReader<helloworld::HelloReply>&, helloworld::HelloReply&, CompletionToken).

Instead of the void* tag in the gRPC API the functions in this library expect a CompletionToken. Asio comes with several CompletionTokens already: C++20 coroutine, stackless coroutine, callback and Boost.Coroutine. There is also a special token created by agrpc::use_sender(scheduler) that causes RPC functions to return a TypedSender.

If you are interested in learning more about the implementation details of this library then check out this blog article.

Getting started

Getting started

Start by creating a agrpc::GrpcContext.

For servers and clients:

grpc::ServerBuilder builder;
agrpc::GrpcContext grpc_context{builder.AddCompletionQueue()};

snippet source | anchor

For clients only:

agrpc::GrpcContext grpc_context{std::make_unique<grpc::CompletionQueue>()};

snippet source | anchor

Add some work to the grpc_context and run it. Make sure to shutdown the server before destructing the grpc_context. Also destruct the grpc_context before destructing the server. A grpc_context can only be run on one thread at a time.

grpc_context.run();
server->Shutdown();
}  // grpc_context is destructed here before the server

snippet source | anchor

It might also be helpful to create a work guard before running the agrpc::GrpcContext to prevent grpc_context.run() from returning early.

auto guard = asio::make_work_guard(grpc_context);

snippet source | anchor

Where to go from here?

Check out the examples and the API documentation.

What users are saying

Asio-grpc abstracts away the implementation details of asynchronous grpc handling: crafting working code is easier, faster, less prone to errors and considerably more fun. At 3YOURMIND we reliably use asio-grpc in production since its very first release, allowing our developers to effortlessly implement low-latency/high-throughput asynchronous data transfer in time critical applications.

@3YOURMIND

Our project is a real-time distributed motion capture system that uses your framework to stream data back and forward between multiple machines. Previously I have tried to build a bidirectional streaming framework from scratch using only gRPC. However, it's not maintainable and error-prone due to a large amount of service and streaming code. As a developer whose experienced both raw grpc and asio-grpc, I can tell that your framework is a real a game-changer for writing grpc code in C++. It has made my life much easier. I really appreciate the effort you have put into this project and your superior skills in designing c++ template code.

@khanhha

asio-grpc's People

Contributors

actions-user avatar tradias avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.