grpc 当前版本的 C++ async API, 是基于 completion queue 实现的.
- 首先在 api 设计上, 对于单次 rpc 调用, 这个 completion queue 只能有两个, 分别是 call 和 notification(grpc 起的名字), 读写事件只能在 call 这一个 completion queue 回调
- completion queue 事件返回时会带有一个标识. 在官方的 demo 中, 这个标识用来标记是哪个对象产生了事件. 你想通过这个标识同时区分到底是哪种事件产生, 是不可能了.
- 简单来说, completion queue 返回的值, 只有一个, 这个值在有些 demo(官方) 里被用来标记对象, 有些 demo(网上的一些例子) 里被用来标记事件, 可是我写基于 stream(也就是 N 个请求 N 个返回) 的长连接, 需要同时获得这两个信息啊
- 如果参照 libevent 之类的办法, 最起码应该分别有"读"/"写"以及"连接事件"的 completion queue
- 可能官方也不知道怎么处理最好, 唯一的 async api demo 是不包含 stream 的, 简单的单次 rpc 调用
为了解决这个问题, 我只好用一个"全局唯一的 uint64 id"标识对象, 并在分配 id 的时候做了区间划分, 比如 * id + 0 用来标识 "连接创建事件"
- id + 1 用来标识 "读完成事件"
- id + 2 用来标识 "写完成事件"
- id + 3 用来标识 "连接关闭事件"
然后下一个新的对象 id , 在上一个 id 的基础上 + 4
这是我的 demo:
https://github.com/DinoStray/grpc_example_async_cpp_api
关于这个问题, 几年前就有人开始吐槽(描述的问题和我一模一样)
https://groups.google.com/forum/#!topic/grpc-io/7P8QvBBNq_E
grpc 官方也给了回应, 并表示将优化 api
https://github.com/grpc/grpc/issues/7352
可是 2016 年的回应, 都过去 4 年了, 还没完成....吐血