Ocaml Lwt.wait()

У меня есть вопрос о функции ожидания lwt и о том, как я буду использовать ее в своей собственной пользовательской функции, которая будет возвращать поток Lwt.t. Сначала давайте покажем вам пример.

open Lwt_io
open Lwt.Infix

let i, o = Lwt_io.pipe()

let get_int () =
  let t, w = Lwt.wait() in
  (*what do I do here to provide the sleeping thread*)
  (*with a possible integer reply*)
  Lwt_io.read_int(i) >>= fun i -> Lwt.wakeup w i;
  t

let ans = get_int()

В приведенной выше функции я вызываю wait, чтобы создать спящий поток плюс его wakener, но я не уверен, как предоставить спящему потоку возможный целочисленный ответ и все же иметь возможность вернуть спящий поток из функции get_int. Я предоставил строку (Lwt_io.read_int(i) >>= fun i -> Lwt.wakeup w i;), которая работает, но я не уверен, что это правильный способ для достижения этой цели. Любые указатели или ссылки или комментарии?

Примечание: я спрашиваю, потому что добавление Lwt_io.read_int (i) в функцию является излишним. Я мог бы просто исключить функцию get_int и просто вызвать Lwt_io.read_int (i), но мне любопытно, как бы вы сделали это без избыточности.

1 ответ

Решение

Прежде всего, давайте перейдем к новой терминологии Lwt. Согласно новой терминологии, принятой в библиотеке Lwt, Lwt.wait Функция возвращает обещание и распознаватель.

Это довольно низкоуровневый интерфейс, который обычно используется для реализации более высокоуровневых интерфейсов. И действительно, в вашем случае, get_int функция может быть реализована как раз Lwt_io.read_int,

Итак, ради эксперимента давайте реализуем кое-что, что имеет немного больше смысла:

let wait () =
   let promise, resolver = Lwt.wait () in
   Lwt.async (fun () ->
      Lwt_unix.sleep (Random.float 1.0) >|= 
      Lwt.wakeup resolver);
   promise

наш wait Функция возвращает обещание, которое будет выполнено после случайной задержки. Вы можете видеть, что есть вызов Lwt.async который возьмет thunk и выполнит его в обработчике событий асинхронно, таким образом, функция wait возвращается немедленно. Конечно, этот пример не имеет большого смысла, так как функция с той же семантикой может быть реализована так:

let wait () = Lwt_unix.sleep 1.0

Но это только показывает, что wait Функция нужна только для реализации примитивов Lwt.

Одним из оправданных вариантов использования этого интерфейса является необходимость разделения поставщика услуг и потребителя. Тогда вы можете использовать Lwt.wait (или даже лучше Lwt.add_task_*например,

module Broker = sig 
  type 'a t
  val request : 'a t -> 'a Lwt.t
  val provide : 'a t -> 'a -> unit
end = struct 
  type 'a t = {mutable requested : 'a Lwt.u option}

  let request broker = 
     let promise, request = Lwt.wait () in
     broker.requested <- Some request;
     promise

  let provide broker data = match broker.requested with
    | None -> ()
    | Some request -> Lwt.wakeup request data
end

Конечно, мы просто переопределили почтовый ящик (это еще одно доказательство того, что нам обычно не нужно идти так низко, так как все уже сделано для нас), но в целом, когда у вас есть несколько запросов, и вы хотите реализовать ваше собственное планирование их, затем вы можете использовать этот низкоуровневый интерфейс.

Другие вопросы по тегам