Есть ли способ получить ссылку на контекст текущей задачи в асинхронной функции в rust? - PullRequest
0 голосов
/ 12 октября 2019

В асинхронной функции ржавчины есть ли способ получить доступ к текущему Контексту без написания явной реализации Future?

1 Ответ

0 голосов
/ 12 октября 2019

Прежде чем ответить на вопрос, полезно вспомнить, что такое Context;всякий раз, когда вы пишете реализацию Future, которая зависит от внешних ресурсов (скажем, ввода-вывода), вы не хотите ничего занятого ждать. В результате у вас, скорее всего, будут реализации Future, где вы вернете Pending, а затем разбудите его. ContextWaker) существуют для этой цели.

Однако это то, чем они являются: низкоуровневые, подробности реализации. Если вы уже используете Future в отличие от написания низкоуровневой реализации, то, скорее всего, Waker будет содержаться где-то , но не будет напрямую доступно для вас.

В результате этого утечка Waker напрямую является утечкой деталей реализации в 99,9% случаев и фактически не рекомендуется. Однако, Waker, используемый как часть большего struct, прекрасно работает, но именно здесь вам нужно будет реализовать свой собственный Future с нуля. Нет другого действительного варианта использования для этого , и в обычных условиях вам никогда не потребуется прямой доступ к Waker.

Из-за ограничений игровой площадки я, к сожалению, не могупокажу вам живой пример того, когда полезно получить это Waker;однако, такая будущая установка может использоваться в такой ситуации: давайте предположим, что мы строим входную дверь дома. У нас есть дверной звонок и дверь, и мы хотим получать уведомления, когда кто-то звонит в дверь. Однако мы не хотим ждать посетителей у входа.

Поэтому мы создаем два объекта: FrontDoor и Doorbell, и мы даем возможность wire() the Doorbell для соединения двух.

pub struct FrontDoor {
    doorbell: Arc<RwLock<Doorbell>>
}

impl FrontDoor {
    pub fn new() -> FrontDoor {
        FrontDoor {
            doorbell: Arc::new(RwLock::new(Doorbell {
                waker: None,
                visitor: false
            }))
        }
    }
    pub fn wire(&self) -> Arc<RwLock<Doorbell>> {
        self.doorbell.clone() // We retrieve the bell
    }
}

impl Future for FrontDoor {

    type Output = ();

    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
        self.doorbell.read().map(|guard| {
            match guard.visitor {
                true => Poll::Ready(()),
                false => Poll::Pending
            }
        }).unwrap_or(Poll::Pending)
    }
}


pub struct Doorbell {
    waker: Option<Waker>,
    pub visitor: bool
}

impl Doorbell {
    pub fn ring(&mut self) {
        self.visitor = true;
        self.waker.as_ref().map(|waker| waker.wake_by_ref());
    }
}

Наши FrontDoor реализуют Future, что означает, что мы можем просто бросить его на исполнителя по вашему выбору;waker содержится в объекте Doorbell и позволяет нам «звонить» и пробуждать наше будущее.

...