2

我实现了 tonic helloworld教程。然后我尝试更改客户端代码,以便在等待任何请求之前发送多个请求。

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let num_requests = 10;
    let mut client = GreeterClient::connect("http://[::1]:50051").await?;

    let mut responses = Vec::with_capacity(num_requests);
    for _ in 0..num_requests {
        let request = tonic::Request::new(HelloRequest {
            name: "Tonic".into(),
        });

        responses.push(client.say_hello(request));
    }
    for resp in responses {
        assert!(resp.await.is_ok());
    }

    Ok(())
}

这会导致编译错误:

error[E0499]: cannot borrow `client` as mutable more than once at a time
  --> src/client.rs:19:24
   |
19 |         responses.push(client.say_hello(request));
   |                        ^^^^^^ mutable borrow starts here in previous iteration of loop

这是否意味着'client.say_hello()'返回一个仍然引用客户端的类型,因此我不能再次调用'say_hello',它本身需要'&mut self'?有没有办法在调用“等待”之前继续提出请求?

4

1 回答 1

5

补品文档

在通道上发送请求需要一个&mut self,因此只能在飞行中发送一个请求。这是故意的,并且需要遵循构建此通道实现的库中的Service合同。 ... 为了解决这个问题并简化通道的使用,提供了一种廉价的实现。这是因为在最顶层,通道由在后台任务中运行连接并提供通道接口的 a 支持。由于这种克隆,该类型便宜且受鼓励。tower

ChannelClonetower_buffer::BuffermpscChannel

因此,您可以为您发出的每个并发请求克隆客户端。这消除了单个客户在任何给定时间多次被可变借用的可能性,因此借用检查器被安抚了。

let num_requests = 10;
let client = GreeterClient::connect("http://[::1]:50051").await?;

let mut responses = Vec::with_capacity(num_requests);

for _ in 0..num_requests {
    let mut client = client.clone();

    let request = tonic::Request::new(HelloRequest {
        name: "Tonic".into(),
    });

    responses.push(tokio::spawn(async move {
        client.say_hello(request).await
    }));
}

for resp in responses {
    let resp = resp.await;
    assert!(resp.is_ok());
    assert!(resp.unwrap().is_ok());
}
于 2021-01-29T17:53:49.487 回答