英文:
how can I use a random number and a tokio::time::sleep within an async function in rust
问题
以下是已翻译的内容:
我有一个 gRPC 服务器方法,我想模拟一些工作,为此我有以下代码:
async fn write(&self, request: Request<WriteRequest>)
-> Result<Response<WriteResponse>, Status> {
let mut rng = rand::thread_rng();
let random = rng.gen_range(1000..5000);
// Sleep for the random duration
sleep(Duration::from_millis(random)).await;
return Ok(Response::new(WriteResponse { ... }));
}
但是代码对于随机值感到不满意,我收到以下错误信息:
未能安全地在线程之间发送 future 由 async 块创建的 future 不是 `Send`
我知道我可以在函数中添加 + Send,但在这种情况下,我无法修改由 gRPC 编译器生成的方法签名。
当我在 Duration 中使用硬编码值时,它可以正常工作。
如何调用随机数生成?或者如何使用 sleep 休眠一个随机值?是否有其他方法?
<details>
<summary>英文:</summary>
I have a gRPC server method for which I want to simulate some work for this I have this
async fn write(&self, request: Request<WriteRequest>)
-> Result<Response<WriteResponse>, Status> {
let mut rng = rand::thread_rng();
let random = rng.gen_range(1000..5000);
// Sleep for the random duration
sleep(Duration::from_millis(random)).await;
return Ok(Response::new(WriteResponse { ... }));
}
but the code is not happy about the random value, I get the error
future cannot be sent between threads safely future created by async block is not Send
I know I can add + Send in the function but in this case, I cannot modify the signature of the method because it is an interface generated by the gRPC compiler
When I used hardcoded value within the Duration in works.
How can I call the random number generation? or how can I sleep for a random value using sleep? is there another way?
</details>
# 答案1
**得分**: 4
这是因为 `rng` 超过了一个等待点而发生的。您可以通过将其封装在一个块中来解决这个问题,这样可以确保它不会存储在异步函数的状态机中。
```rs
let random_secs = {
let mut rng = rand::thread_rng();
rng.gen_range(1000..5000)
};
如果您确实需要存储一个 RNG,您可以存储一个由 thread_rng
种子化的普通 PRNG(如 StdRng
)。
use rand::{Rng, SeedableRng, rngs::StdRng};
let mut rng = {
let rng = rand::thread_rng();
StdRng::from_rng(rng).unwrap()
};
loop {
let millis = rng.gen_range(1..10);
tokio::time::sleep(std::time::Duration::from_millis(millis)).await;
println!("{millis}");
}
英文:
This happens because rng
is held past an await point. You can get around this by enclosing it in a block, which ensures it is not stored in the async function's state machine.
let random_secs = {
let mut rng = rand::thread_rng();
rng.gen_range(1000..5000)
};
If you do need to store an RNG, you can store a normal PRNG (such as StdRng
) that is seeded from thread_rng
.
use rand::{Rng, SeedableRng, rngs::StdRng};
let mut rng = {
let rng = rand::thread_rng();
StdRng::from_rng(rng).unwrap()
};
loop {
let millis = rng.gen_range(1..10);
tokio::time::sleep(std::time::Duration::from_millis(millis)).await;
println!("{millis}");
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论