Consider the following ghetto_select for reading from channels - a HashMap of Receivers. First, it creates a random permutation of the list of keys. Then it drops the representation of the source of randomness rng (or so I hoped). And finally, it goes over channels and does its thing. The "thing" involves an await in an error case. Somehow, a ThreadRng needs to be carried over the await, which it can't.
async fn ghetto_select(channels: &mut HashMap>>) -> (u64, Arc) {
let mut rng = &mut rand::rng();
let ids = channels
.keys()
.map( |e| *e )
.sample(&mut rng, channels.len());
// shouldn't rng be gone now?
drop(rng);
// TODO the random order might be a big hit. perhaps cyclic+resuming from the previous position is better
loop {
for id in &ids {
// don't know why it wouldn't but let's be safe
let c = match channels.get_mut(id) {
Some(n) => c,
None => continue,
};
match c.try_recv() {
Ok(v) => return (*id, v),
Err(broadcast::error::TryRecvError::Empty) => continue,
Err(broadcast::error::TryRecvError::Closed) => {
recover(id, channels).await;
},
Err(broadcast::error::TryRecvError::Lagged ( _count )) => {
// do nothing here. rely on end-to-end mechanism to detect holes
},
}
}
// TODO adapt interval?
tokio::time::sleep(Duration::from_millis(10)).await;
}
}
This is what the compiler says:
Compiling await-scope-test v0.1.0 (/media/git/await-scope-test)
error: future cannot be sent between threads safely
--> src/consumers.rs:280:5
|
280 | / tokio::spawn(async move {
281 | | let handler = match cl.fetch(jwt).await {
282 | | Ok(handler) => {
283 | | tx.send(Ok(()));
... |
295 | | });
| |__________________^ future created by async block is not `Send`
|
= help: within `{async block@src/consumers.rs:280:18: 280:28}`, the trait `std::marker::Send` is not implemented for `Rc>>`
note: future is not `Send` as this value is used across an await
--> src/consumers.rs:142:51
|
121 | let mut rng = &mut rand::rng();
| ----------- has type `ThreadRng` which is not `Send`
...
142 | recover(id, channels).await;
| ^^^^^ await occurs here, with `rand::rng()` maybe used later
note: required by a bound in `tokio::spawn`
--> /home/me/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.49.0/src/task/spawn.rs:171:21
|
169 | pub fn spawn(future: F) -> JoinHandle
| ----- required by a bound in this function
170 | where
171 | F: Future + Send + 'static,
| ^^^^ required by this bound in `spawn`
error: could not compile `await-scope-test` (bin "await-scope-test") due to 1 previous error
Shouldn't the drop prevent the value from being 'leaked'?