跳到主要内容

Notify

搜索

结构体 Notify 

Source
pub struct Notify { /* private fields */ }
展开描述

通知单个 task 唤醒。

Notify 提供了 将事件 通知给 单个任务的 基本机制。 Notify 本身 不携带任何数据。 相反, 它用于 通知 另一个任务 执行 某个操作。

可以将 Notify 视为 从 0 个 permit 开始的 Semaphorenotified().await 方法 等待 permit 变为可用, 而 notify_one()如果当前没有可用的 permit 设置 一个 permit。

Notify 的 同步细节 类似于 std 中的 thread::parkThread::unparkNotify 值 包含 单个 permit。 notified().await 等待 permit 变为可用, 消费 该 permit, 然后恢复。 notify_one() 设置 该 permit, 如果存在 挂起的任务, 则唤醒它。

如果 notify_one() 被调用 notified().await 之前, 那么 下一次 对 notified().await 的调用 将立即完成, 消耗 该 permit。 之后 任何对 notified().await 的调用 将 等待 新的 permit。

如果 notify_one()notified().await 之前 被调用 多次, 则 仅存储 一个 permit。 下一次 对 notified().await 的调用 将 立即完成, 但 之后 将 等待 新的 permit。

§示例

基本用法。

use tokio::sync::Notify;


use std::sync::Arc;





let notify = Arc::new(Notify::new());


let notify2 = notify.clone();





let handle = tokio::spawn(async move {


    notify2.notified().await;


    println!("received notification");


});





println!("sending notification");


notify.notify_one();





// Wait for task to receive notification.


handle.await.unwrap();

无界 多生产者单消费者 (mpsc) 通道。

使用 此通道时, 不会丢失 任何唤醒, 因为 对 notify_one() 的调用 会在 Notify 中存储一个 permit, 随后的 对 notified() 的调用 会 消费该 permit。

use tokio::sync::Notify;





use std::collections::VecDeque;


use std::sync::Mutex;





struct Channel<T> {


    values: Mutex<VecDeque<T>>,


    notify: Notify,


}





impl<T> Channel<T> {


    pub fn send(&self, value: T) {


        self.values.lock().unwrap()


            .push_back(value);





        // Notify the consumer a value is available


        self.notify.notify_one();


    }





    // This is a single-consumer channel, so several concurrent calls to


    // `recv` are not allowed.


    pub async fn recv(&self) -> T {


        loop {


            // Drain values


            if let Some(value) = self.values.lock().unwrap().pop_front() {


                return value;


            }





            // Wait for values to be available


            self.notify.notified().await;


        }


    }


}

无界 多生产者多消费者 (mpmc) 通道。

调用 enable 很重要, 因为 否则 如果你 并行地 有两个 对 recv 的调用 和 两个 对 send 的调用, 可能会发生 以下情况:

  1. Both calls to try_recv return None.
  2. Both new elements are added to the vector.
  3. The notify_one method is called twice, adding only a single permit to the Notify.
  4. Both calls to recv reach the Notified future. One of them consumes the permit, and the other sleeps forever.

通过在 try_recv 之前调用 enableNotified future 添加到列表中, 步骤三中的 notify_one 调用 会 从列表中移除 这些 future, 并将它们 标记为已通知, 而不是 向 Notify 添加 permit。 这 确保 两个 future 都会被唤醒。

请注意, 此失败 仅在 有两个 对 recv 的并发调用时 才会发生。 这就是 上面的 mpsc 示例 不需要调用 enable 的原因。

use tokio::sync::Notify;





use std::collections::VecDeque;


use std::sync::Mutex;





struct Channel<T> {


    messages: Mutex<VecDeque<T>>,


    notify_on_sent: Notify,


}





impl<T> Channel<T> {


    pub fn send(&self, msg: T) {


        let mut locked_queue = self.messages.lock().unwrap();


        locked_queue.push_back(msg);


        drop(locked_queue);





        // Send a notification to one of the calls currently


        // waiting in a call to `recv`.


        self.notify_on_sent.notify_one();


    }





    pub fn try_recv(&self) -> Option<T> {


        let mut locked_queue = self.messages.lock().unwrap();


        locked_queue.pop_front()


    }





    pub async fn recv(&self) -> T {


        let future = self.notify_on_sent.notified();


        tokio::pin!(future);





        loop {


            // Make sure that no wakeup is lost if we get


            // `None` from `try_recv`.


            future.as_mut().enable();





            if let Some(msg) = self.try_recv() {


                return msg;


            }





            // Wait for a call to `notify_one`.


            //


            // This uses `.as_mut()` to avoid consuming the future,


            // which lets us call `Pin::set` below.


            future.as_mut().await;





            // Reset the future in case another call to


            // `try_recv` got the message before us.


            future.set(self.notify_on_sent.notified());


        }


    }


}

实现§

Source§

impl Notify

Source

pub fn new() -> Notify

创建一个新的 Notify,初始化时没有许可证。

§示例
use tokio::sync::Notify;





let notify = Notify::new();
Source

pub const fn const_new() -> Notify

创建一个新的 Notify,初始化时没有许可证。

使用 tracing 不稳定特性时,通过 const_new 创建的 Notify 不会被插桩。因此,它不会出现在 tokio-console 中。如有需要,请改用 Notify::new 来创建可插桩的对象。

§示例
use tokio::sync::Notify;





static NOTIFY: Notify = Notify::const_new();
Source

pub fn notified(&self) -> Notified<'_>

等待通知。

等价于:

async fn notified(&self);

每个 Notify 值持有一个许可证。如果之前调用 notify_one() 后还有可用的许可证,那么 notified().await 会立即完成并消费该许可证。否则,notified().await 等待下一次调用 notify_one() 来提供许可证。

如果 Notified future 还未被 poll,则不能保证它能收到 notify_one() 调用的唤醒。详见 Notified::enable() 的文档。

Notified future 一旦被创建就能保证收到 notify_waiters() 的唤醒,即使它还未被 poll。

§Cancel safety

此方法使用队列按请求顺序公平分发通知。取消对 notified 的调用会丢失在队列中的位置。

§示例
use tokio::sync::Notify;


use std::sync::Arc;





let notify = Arc::new(Notify::new());


let notify2 = notify.clone();





tokio::spawn(async move {


    notify2.notified().await;


    println!("received notification");


});





println!("sending notification");


notify.notify_one();
Source

pub fn notified_owned(self: Arc<Self>) -> OwnedNotified

使用拥有的 Future 等待通知。

Self::notified 返回绑定到 Notify 生命周期的 future 不同,notified_owned 创建一个独立的 future,它拥有自己的通知状态,因此可以安全地在线程间移动。

详见 Self::notified

§Cancel safety

此方法使用队列按请求顺序公平分发通知。取消对 notified_owned 的调用会丢失在队列中的位置。

§示例
use std::sync::Arc;


use tokio::sync::Notify;





let notify = Arc::new(Notify::new());





for _ in 0..10 {


    let notified = notify.clone().notified_owned();


    tokio::spawn(async move {


        notified.await;


        println!("received notification");


    });


}





println!("sending notification");


notify.notify_waiters();
Source

pub fn notify_one(&self)

通知第一个等待的任务。

如果当前有任务正在等待,该任务将被通知。否则,一个许可证会存储到此 Notify 值中,下一次调用 notified().await 将立即完成并消费本次 notify_one() 调用所提供的许可证。

Notify 最多只能存储一个许可证。多次连续调用 notify_one 只会存储一个许可证。下一次调用 notified().await 会立即完成,但再下一次则会等待。

§示例
use tokio::sync::Notify;


use std::sync::Arc;





let notify = Arc::new(Notify::new());


let notify2 = notify.clone();





tokio::spawn(async move {


    notify2.notified().await;


    println!("received notification");


});





println!("sending notification");


notify.notify_one();
Source

pub fn notify_last(&self)

通知最后一个等待的任务。

此函数行为与 notify_one 类似。唯一区别是它唤醒最近添加的等待者而不是最早添加的。

请参阅 notify_one() 的文档以获取更多信息和示例。

Source

pub fn notify_waiters(&self)

通知所有等待的任务。

如果当前有任务正在等待,该任务将被通知。与 notify_one() 不同的是,此方法不会存储许可证供下一次 notified().await 使用。此方法的目的是通知所有已注册的等待者。注册的通过调用 notified() 获取 Notified future 实例完成。

§示例
use tokio::sync::Notify;


use std::sync::Arc;





let notify = Arc::new(Notify::new());


let notify2 = notify.clone();





let notified1 = notify.notified();


let notified2 = notify.notified();





let handle = tokio::spawn(async move {


    println!("sending notifications");


    notify2.notify_waiters();


});





notified1.await;


notified2.await;


println!("received notifications");

Trait 实现§

Source§

impl Debug for Notify

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

使用给定的格式化器格式化此值。 更多信息
Source§

impl Default for Notify

Source§

fn default() -> Notify

Returns the “default value” for a type. 更多信息
Source§

impl RefUnwindSafe for Notify

Source§

impl UnwindSafe for Notify

自动 Trait 实现§

§

impl !Freeze for Notify

§

impl Send for Notify

§

impl Sync for Notify

§

impl Unpin for Notify

§

impl UnsafeUnpin for Notify

Blanket 实现§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. 更多信息
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. 更多信息
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. 更多信息
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

原样返回传入的参数。

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

调用 U::from(self)

也就是说,此转换的具体行为取决于 From<T> for U 的实现方式。

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

转换出错时返回的类型。
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

执行转换。
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

转换出错时返回的类型。
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

执行转换。