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