如何在Rust的异步函数中使用随机数和tokio::time::sleep?

huangapple go评论105阅读模式
英文:

how can I use a random number and a tokio::time::sleep within an async function in rust

问题

以下是已翻译的内容:

  1. 我有一个 gRPC 服务器方法,我想模拟一些工作,为此我有以下代码:
  2. async fn write(&self, request: Request<WriteRequest>)
  3. -> Result<Response<WriteResponse>, Status> {
  4. let mut rng = rand::thread_rng();
  5. let random = rng.gen_range(1000..5000);
  6. // Sleep for the random duration
  7. sleep(Duration::from_millis(random)).await;
  8. return Ok(Response::new(WriteResponse { ... }));
  9. }

但是代码对于随机值感到不满意,我收到以下错误信息:

  1. 未能安全地在线程之间发送 future async 块创建的 future 不是 `Send`

我知道我可以在函数中添加 + Send,但在这种情况下,我无法修改由 gRPC 编译器生成的方法签名。

当我在 Duration 中使用硬编码值时,它可以正常工作。

如何调用随机数生成?或者如何使用 sleep 休眠一个随机值?是否有其他方法?

  1. <details>
  2. <summary>英文:</summary>
  3. I have a gRPC server method for which I want to simulate some work for this I have this
  4. async fn write(&amp;self, request: Request&lt;WriteRequest&gt;)
  5. -&gt; Result&lt;Response&lt;WriteResponse&gt;, Status&gt; {
  6. let mut rng = rand::thread_rng();
  7. let random = rng.gen_range(1000..5000);
  8. // Sleep for the random duration
  9. sleep(Duration::from_millis(random)).await;
  10. return Ok(Response::new(WriteResponse { ... }));
  11. }
  12. 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

  1. 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
  2. When I used hardcoded value within the Duration in works.
  3. How can I call the random number generation? or how can I sleep for a random value using sleep? is there another way?
  4. </details>
  5. # 答案1
  6. **得分**: 4
  7. 这是因为 `rng` 超过了一个等待点而发生的。您可以通过将其封装在一个块中来解决这个问题,这样可以确保它不会存储在异步函数的状态机中。
  8. ```rs
  9. let random_secs = {
  10. let mut rng = rand::thread_rng();
  11. rng.gen_range(1000..5000)
  12. };

如果您确实需要存储一个 RNG,您可以存储一个由 thread_rng 种子化的普通 PRNG(如 StdRng)。

  1. use rand::{Rng, SeedableRng, rngs::StdRng};
  2. let mut rng = {
  3. let rng = rand::thread_rng();
  4. StdRng::from_rng(rng).unwrap()
  5. };
  6. loop {
  7. let millis = rng.gen_range(1..10);
  8. tokio::time::sleep(std::time::Duration::from_millis(millis)).await;
  9. println!("{millis}");
  10. }
英文:

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.

  1. let random_secs = {
  2. let mut rng = rand::thread_rng();
  3. rng.gen_range(1000..5000)
  4. };

If you do need to store an RNG, you can store a normal PRNG (such as StdRng) that is seeded from thread_rng.

  1. use rand::{Rng, SeedableRng, rngs::StdRng};
  2. let mut rng = {
  3. let rng = rand::thread_rng();
  4. StdRng::from_rng(rng).unwrap()
  5. };
  6. loop {
  7. let millis = rng.gen_range(1..10);
  8. tokio::time::sleep(std::time::Duration::from_millis(millis)).await;
  9. println!(&quot;{millis}&quot;);
  10. }

huangapple
  • 本文由 发表于 2023年6月8日 00:35:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/76425432.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定