rust 循环中的时雄::select!A,B和tokio::spawn两个任务分别运行A,B中的一个有什么区别?

cbwuti44  于 2023-02-23  发布在  其他
关注(0)|答案(1)|浏览(254)

我是异步编程的新手,因此很难理解不同的方法在行为上的差异。
考虑一下时雄在github repo(www.example.com)上给出的例子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

在两个时雄::spawn上使用循环select!的好处是什么,如下所示:

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
c2e8gylq

c2e8gylq1#

总的来说,select!更高效,因为它不需要产生新任务,这非常便宜,但仍然比轮询future昂贵。
1.如果频繁出现消息,使任务更受CPU限制,则建议派生一个新任务,因为select!在同一线程上运行所有future,而spawn()可能在多线程运行时使用不同的线程。

  1. select!中的future应该是 cancellation-safe,这意味着删除未完成的future是安全的,并且不会导致任何数据丢失。如果不是这样,可能会有bug。这使得用select!编程比用任务编程更困难。例如,请参见this post

相关问题