3

The rng crate is neither Sync nor Send, so the rng::thread_rng can not cross the .await point. What is the simplest and beautiful way to generate random numbers in async rust?

Generating A lot of numbers beforehead and then use them is ugly.

Myrfy
  • 575
  • 4
  • 11
  • Confusingly, the handle returned by `thread_rng` seems to compile being transferred across await [in this playground example](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=10c50d45cbeecbc2f28133e776a10fa0). I'm not sure what's up with that. – user4815162342 May 08 '21 at 07:44
  • 3
    But you could always create your own proper rng, e.g. using `let mut rng: StdRng = SeedableRng::from_entropy()`, as shown in [this answer](https://stackoverflow.com/a/65053773/1600898). That will give you something that is not just a handle to a thread-local and should be Send+Sync. – user4815162342 May 08 '21 at 07:46
  • @user4815162342 thanks for the answer. I used StdRng in an async tokio stream and it works flawless. – Daniel Leiszen Jan 07 '23 at 23:08
  • 1
    @DanielLeiszen Glad it helped. To answer my own question from the first comment, awaiting a non-send future works in `main()` because main itself gets run in the main thread, which is why Tokio can get away with not requiring that the future it produces be `Send`. However, if you try something like `tokio::spawn(async { foo().await })`, it will fail to compile, as expected. – user4815162342 Jan 08 '23 at 10:41

2 Answers2

4

From the tokio Discord

let random = rand::random::<i64>();

or

let random = {
    let mut rng = rand::thread_rng();
    rng.gen::<i64>()
}

"make sure the rng variable falls out of scope before you use an await"

Pmimo
  • 61
  • 3
0

Getting a new rng handle is cheap. A rng will be created once per thread (when used), and after that ThreadRng::default only uses LocalKey::with and Rc::clone. Do you need to keep the previous state so the number sequence is repeatable?

piojo
  • 6,351
  • 1
  • 26
  • 36