简体   繁体   中英

How do I pass these references to a function that spawns a tokio task?

I have a bit of code that works exactly as intended:

pub async fn start(num_websockets: i32) {
    let messages_received = Arc::new(Mutex::new(0));
    let (shutdown_signal, _) = broadcast::channel(1);
    let (done, mut wait_for_tasks) = channel::<&str>(1);
    tokio::spawn(stats::message_counter(
        Arc::clone(&messages_received),
        shutdown_signal.subscribe(),
        done.clone(),
    ));
    for _i in 0..num_websockets {
        let (ws_stream, _) = websocket::connect().await.unwrap();
        let (mut write, read) = ws_stream.split();
        subscription::subscribe(&mut write, "book.BTC-PERPETUAL.100ms")
            .await
            .unwrap();
        tokio::spawn(websocket::listener(
            read,
            messages_received.clone(),
            shutdown_signal.subscribe(),
            done.clone(),
        ));
    }

In the for loop, I spawn an arbitrary amount of websocket::listener , that will shutdown when receiving the shutdown_signal and let main know when they're done through done .

When I try to extract this code to a function, like so:

...
    for _i in 0..num_websockets {
        subscribe_and_listen(messages_received.clone(), shutdown_signal.subscribe(), done.clone());
    }
...

async fn subscribe_and_listen(messages_received: Arc<Mutex<i32>>,
                              shutdown_signal: broadcast::Receiver<&str>,
                              done: mpsc::Sender<&str>) {
    let (ws_stream, _) = websocket::connect().await.unwrap();
    let (mut write, read) = ws_stream.split();
    subscription::subscribe(&mut write, "book.BTC-PERPETUAL.100ms")
        .await
        .unwrap();
    tokio::spawn(
        websocket::listener(
            read,
            messages_received.clone(),
            shutdown_signal,
            done.clone(),
        )
    );
}

The compiler tells me:

error[E0759]: `shutdown_signal` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
   --> src/benchmark.rs:21:9
    |
13  |                                 shutdown_signal: broadcast::Receiver<&str>,
    |                                                  ------------------------- this data with an anonymous lifetime `'_`...
...
21  | /         websocket::listener(
22  | |             read,
23  | |             messages_received.clone(),
24  | |             shutdown_signal,
    | |             --------------- ...is used here...
25  | |             done.clone(),
26  | |         )
    | |_________^
    |
note: ...and is required to live as long as `'static` here
   --> src/benchmark.rs:20:5
    |
20  |     tokio::spawn(
    |     ^^^^^^^^^^^^
note: `'static` lifetime requirement introduced by this bound
   --> /Users/b0nes/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.20.0/src/task/spawn.rs:127:28
    |
127 |         T: Future + Send + 'static,

I have tried many things, but I simply cannot move this bit of code to a function, and I really want to understand how to do this. It seems to me that there is no need for anything to be 'static , as the function can take full ownership over the results of shutdown_signal.subscribe() and done.clone()

The solution is to use a String for the channels shutdown_signal and done , or some other type that satisfies 'static, such as a &'static str.

In my case I didn't actually need to provide any strings so I just made a channel with () .

The problem was, &str cannot be owned, but that is exactly what the tokio::spawn task requires.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM