在循环内使用tokio::select! A, B和使用tokio::spawn两个任务分别运行A、B有什么区别?

3

我是异步编程的新手,因此在不同的方法行为上挣扎。

考虑一下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

使用loop 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
1个回答

4
一般来说,select! 更有效率,因为它不需要生成新的任务,这非常便宜但仍然比轮询未来更昂贵。但是,有几个注意事项:
  1. 如果有频繁的消息,使得任务更加 CPU 绑定,则建议生成新任务,因为 select! 在同一线程上运行所有未来,而 spawn() 可能在多线程运行时使用不同的线程。

  2. select! 中的未来应该是取消安全的,意味着可以安全地放弃它们,并且这不会导致任何数据丢失。如果不是这种情况,可能会出现错误。与任务相比,使用 select! 更难编程。例如,请参见此帖子


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接