Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

coro_rpc支持协程接口通过cgo被go app调用 #910

Open
helintongh opened this issue Mar 3, 2025 · 4 comments
Open

coro_rpc支持协程接口通过cgo被go app调用 #910

helintongh opened this issue Mar 3, 2025 · 4 comments

Comments

@helintongh
Copy link
Contributor

如题

@qicosmos
Copy link
Collaborator

qicosmos commented Mar 4, 2025

可以讨论一下,先讨论client 用cgo封装的问题。
同步调用相关的c接口类似于这样:

void* create_client() {
  auto client = new coro_rpc::coro_rpc_client();
  return client;
}

int connect_to(void* client, char* host, char* port) {
  auto c = (coro_rpc::coro_rpc_client*)client;
  auto ec = async_simple::coro::syncAwait(c->connect(host, port));
  return !ec;
}

void free_client(void* client) {
  auto c = (coro_rpc::coro_rpc_client*)client;
  delete c;
}

int echo_sync(void* client, char* input) {
  auto c = (coro_rpc::coro_rpc_client*)client;
  std::string_view str(input);
  auto lazy = [&]()->async_simple::coro::Lazy<std::string_view> {
    auto future_resp = co_await c->send_request<echo>(str);
    auto result = co_await std::move(future_resp);
    co_return result.value().result();
  };
  auto sv = async_simple::coro::syncAwait(lazy());
  return (int)sv.size();
}

go通过cgo去调用rpc函数:

var client = C.create_client();
var has_connected = C.connect_to(client, C.CString("0.0.0.0"), C.CString("8801"));
r := C.echo_sync(client, C.CString("hello"));
C.free_client(client);

这样使用最简单,但是调用的同步阻塞接口,在启动多个goroutine 去请求时qps存在瓶颈,加大并发并不能提升qps,这是一个问题。

@qicosmos
Copy link
Collaborator

qicosmos commented Mar 4, 2025

另外一种方式是使用协程回调函数方式:

extern void echo_callback(char* host, int size);

void call_echo_with_callback(void* client, char* input) {
  auto c = (coro_rpc::coro_rpc_client*)client;
  std::string_view str(input);
  [&]()->async_simple::coro::Lazy<void> {
    auto future_resp = co_await c->send_request<echo>(str);
    auto result = co_await std::move(future_resp);
    auto sv = result.value().result();
    echo_callback((char*)sv.data(), (int)sv.size());
  }().start([](auto&& val){
  });
}
type callback_data struct {
  data *C.char
  size C.int
}

var myChannel chan callback_data;

//export echo_callback
func echo_callback(data *C.char, size C.int) {
  myChannel <- callback_data{data, size}
}

func test() {
  var client = C.create_client();
  var has_connected = C.connect_to(client, C.CString("0.0.0.0"), C.CString("8801"));
  C.call_echo_with_callback(client, C.CString("hello"));
  r := <-myChannel;
}

benchmark回调方式比同步调用性能更好,但是需要借助channel中转回调的数据,似乎也不是太好,看看有没有什么更好的方法。

@helintongh
Copy link
Contributor Author

helintongh commented Mar 4, 2025

不使用channel,直接通过unsafe接口直接赋值。
修改为如下:

extern void echo_callback(char* host, int size);

void call_echo_with_callback(void* client, char* input) {
  auto c = (coro_rpc::coro_rpc_client*)client;
  std::string_view str(input);
  [&]()->async_simple::coro::Lazy<void> {
    auto future_resp = co_await c->send_request<echo>(str);
    auto result = co_await std::move(future_resp);
    auto sv = result.value().result();
    echo_callback((char*)sv.data(), (int)sv.size());
  }().start([](auto&& val){
  });
}
// 可能有线程问题,需要pre thread pre str
char *g_str = (char *)malloc(1024);

char *GetStr()
{
  return g_str;
}

typedef void(*echo2_callback)(char *, int*);

void register_callback(echo2_callback cb) {
  g_str = {0};
  int data = 0;
  cb(& g_str, &data);
}

golang端调用:

func goCb(str *C.char, data *C.int)  {
  value1 := C.GetStr();
  go_str := C.GoString(C.GetStr()) // 改成使用全局变量就传递出去了
  value_int := (int)(*data)
  return go_str, value_int
}

C.register_callback((C. call_echo_with_callback)(unsafe.Pointer(C. goCb)))

@qicosmos
Copy link
Collaborator

qicosmos commented Mar 4, 2025

这个return的数据怎么用呢?go 怎么拿这个返回的数据呢?还得通过channel去拿吧。

func goCb(str *C.char, data *C.int)  {
  value1 := C.GetStr();
  go_str := C.GoString(C.GetStr()) // 改成使用全局变量就传递出去了
  value_int := (int)(*data)
  return go_str, value_int
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants