tokio::select! 和 tokio::select! 之间有什么区别?循环内的 A、B 和 tokio::spawn 两个任务,每个任务运行 A、B 之一?

rea*_*hao 3 rust rust-tokio

我是异步编程的新手,因此努力解决不同方法的行为差异。

考虑 tokio 在 github 存储库 chat.rs 中给出的示例:

// snip
    loop {
        tokio::select! {
            // A message was received from a peer. Send it to the current user.
            Some(msg) = peer.rx.recv() => {
                // do something
            }
            result = peer.lines.next() => match result {
                // A message was received from the current user, we should
                // broadcast this message to the other users.
                Some(Ok(msg)) => {
                    // do something
                }
                Some(Err(e)) => {
                    // handle error
                }
                // The stream has been exhausted.
                None => break,
            },
        }
    }
    // do something

Run Code Online (Sandbox Code Playgroud)

使用循环select有什么好处!超过两个 tokio::spawn,如下所示:

    let handle_1 = tokio::spawn(async move {
        while let Some(msg) = peer.rx.recv() {
            // do something
        }
    });
    
    let handle_2 = tokio::spawn (async move {
        loop {
            let result = peer.lines.next();
            match result {
                Some(Ok(msg)) => {
                    // do something
                },
                Some(Err(e)) => {
                    // handle error
                },
                None => break,
            };
        }
    });
    
    handle_1.await;
    handle_2.await;
// do something
Run Code Online (Sandbox Code Playgroud)

Cha*_*man 6

一般来说,select!效率更高,因为它不需要生成新任务,这非常便宜,但仍然比仅仅轮询 future 更昂贵。但是,有一些注意事项:

  1. 如果存在频繁的消息,这使得任务更受 CPU 限制,建议生成一个新任务,因为select!在同一个线程上运行所有 future,而在spawn()多线程运行时可能会使用不同的线程。

  2. 中的期货select!应该是取消安全的,这意味着可以安全地删除未完成的期货,并且这不会导致任何数据丢失。如果不是这种情况,则可能存在错误。它使得select!使用任务编程变得更加困难。例如,请参阅这篇文章。