2017-02-01 16 views
1

Ich habe eine Frage über lwt's Wartefunktion und wie ich es in meiner eigenen benutzerdefinierten Funktion verwenden würde, die einen 'a Lwt.t-Thread zurückgeben würde. Zuerst zeigen wir Ihnen ein Beispiel.Ocaml Lwt.wait()

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() 

In der obigen Funktion warten nenne ich einen Schlaf Faden plus seine wakener zu produzieren, aber ich bin nicht sicher, wie der Schlaf Thread mit einer möglichen ganzzahligen Antwort zu geben und noch einen Schlaf Faden von den get_int zurückkehren können Funktion. Ich habe eine Zeile (Lwt_io.read_int (i) >> = Spaß i -> Lwt.wakeup wi;) zur Verfügung gestellt, die zu funktionieren scheint, aber ich bin mir nicht sicher, ob dies der richtige Weg ist, dies zu erreichen. Irgendwelche Zeiger oder Links oder Kommentare?

Hinweis: Ich frage, weil das Hinzufügen von Lwt_io.read_int (i) zur Funktion redundant ist. Ich könnte einfach die Funktion get_int eliminieren und einfach Lwt_io.read_int (i) aufrufen, aber ich bin gespannt, wie Sie das ohne die Redundanz tun würden.

Antwort

4

Als Erstes wechseln wir zu einer neuen Lwt-Terminologie. Gemäß der neuen Terminologie, die in der Lwt-Bibliothek akzeptiert wurde, gibt die Lwt.wait-Funktion ein Versprechen und einen Resolver zurück.

Dies ist eine ziemlich Low-Level-Schnittstelle, die normalerweise verwendet wird, um mehr High-Level-Schnittstellen zu implementieren. Und in der Tat kann in Ihrem Fall die get_int Funktion als nur Lwt_io.read_int implementiert werden.

Also, im Interesse eines Experiments lassen Sie sich etwas implementieren, die etwas mehr Sinn macht:

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

Unsere wait Funktion gibt ein Versprechen, dass nach einer zufälligen Verzögerung erfüllt werden. Sie können sehen, dass es einen Aufruf an Lwt.async gibt, der ein Thunk nehmen und es im Event-Handler asynchron ausführen wird, so dass eine Funktion wait sofort zurückkehrt. Natürlich ist dieses Beispiel nicht viel mehr Sinn machen, als eine Funktion mit der gleichen Semantik wie umgesetzt werden kann:

let wait() = Lwt_unix.sleep 1.0 

Aber das zeigt nur, dass die wait Funktion nur benötigt wird Lwt Primitiven zu implementieren.

Eine der gerechtfertigten Verwendung dieser Schnittstelle ist, wenn Sie einen Service-Provider und einen Service-Consumer entkoppeln müssen. Dann können Sie Lwt.wait (oder noch besser nutzen Lwt.add_task_* zB

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 

Natürlich haben wir gerade neu implementiert Mailbox (das ist ein weiterer Beweis dafür, dass wir in der Regel nicht, dass niedrig gehen müssen, da alles schon Wenn Sie mehrere Anfragen haben, und Sie Ihre eigene Terminplanung implementieren möchten, können Sie diese Low-Level-Schnittstelle verwenden: