2016-01-21 54 views
2

我正在試驗js_of_ocaml和node.js.如您所知,node.js大量使用回調來實現異步請求,而不引入顯式線程。OCaml/Node.JS上的Lwt.async和Lwt_main.run之間有什麼區別?

在OCaml中,我們有一個非常好的線程庫Lwt,它帶有非常有用的語法擴展。我編寫了一個綁定到某個節點庫(AWS S3客戶端)的原型,並添加了一個lwt-ish圖層來隱藏回調。

open Lwt.Infix 
open Printf 
open Js 

let require_module s = 
    Js.Unsafe.fun_call 
     (Js.Unsafe.js_expr "require") 
     [|Js.Unsafe.inject (Js.string s)|] 

let _js_aws = require_module "aws-sdk" 

let array_to_list a = 
    let ax = ref [] in 
    begin 
    for i = 0 to a##.length - 1 do 
     Optdef.iter (array_get a i) (fun x -> ax := x :: !ax) 
    done; 
    !ax 
    end 


class type error = object 
end 

class type bucket = object 
    method _Name : js_string t readonly_prop 
    method _CreationDate : date t readonly_prop 
end 

class type listBucketsData = object 
    method _Buckets : (bucket t) js_array t readonly_prop 
end 

class type s3 = object 
    method listBuckets : 
    (error -> listBucketsData t -> unit) callback -> unit meth 
end 

let createClient : unit -> s3 t = fun() -> 
    let constr_s3 = _js_aws##.S3 in 
    new%js constr_s3() 


module S3 : sig 
    type t 
    val create : unit -> t 
    val list_buckets : t -> (string * string) list Lwt.t 
end = struct 
    type t = s3 Js.t 

    let create() = 
    createClient() 

    let list_buckets client = 
    let cell_of_bucket_data data = 
     ((to_string data##._Name), 
     (to_string data##._CreationDate##toString)) 
    in 
    let mvar = Lwt_mvar.create_empty() in 
    let callback error buckets = 
     let p() = 
     if true then 
      Lwt_mvar.put mvar 
      (`Ok(List.map cell_of_bucket_data @@ array_to_list buckets##._Buckets)) 
     else 
      Lwt_mvar.put mvar (`Error("Ups")) 
     in 
     Lwt.async p 
    in 
    begin 
     client##listBuckets (wrap_callback callback); 
     Lwt.bind 
     (Lwt_mvar.take mvar) 
     (function 
      | `Ok(whatever) -> Lwt.return whatever 
      | `Error(mesg) -> Lwt.fail_with mesg) 
    end 
end 

let() = 
    let s3 = S3.create() in 
    let dump lst = 
    Lwt_list.iter_s 
     (fun (name, creation_date) -> 
     printf "%32s\t%s\n" name creation_date; 
     Lwt.return_unit) 
     lst 
    in 
    let t() = 
    S3.list_buckets s3 
    >>= dump 
    in 
    begin 
    Lwt.async t 
    end 

由於沒有結合Lwt_main爲node.js的,我不得不與Lwt.async我的代碼運行。運行代碼與Lwt.async而不是Lwt_main.run有什麼區別 - 後者在node.js中不存在?是否保證程序會在退出之前等待異步線程完成,或者這是我的代碼中一個幸運但隨機的行爲?

+0

我從來沒有使用主運行我綁定的NodeJS,頂層單位罰款 –

+0

@EdgarAroutiounian請糾正我,如果我錯了:你寫的綁定不使用LWT可言,對不對?您是否在使用這些綁定的代碼中使用Lwt?也許你想在這裏添加一些答案,以避免聊天。 :) –

+0

我有話要說,但它不是一個真正的答案,有種評論和洞察力。 –

回答

1

Lwt_main.run函數遞歸地輪詢它監督其執行的線程。在每次迭代時,如果此線程仍在運行,則調度程序使用一個引擎(從Lwt_engine)通過選擇或同步事件來執行等待I/O的線程。

在Node.JS中翻譯這種方法的自然方法是使用process.nextTick方法,該方法依賴於Node.JS自己的調度程序。實現在這種情況下,Lwt_main.run功能可以是簡單的:

let next_tick (callback : unit -> unit) = 
    Js.Unsafe.(fun_call 
       (js_expr "process.nextTick") 
       [| inject (Js.wrap_callback callback) |]) 

let rec run t = 
    Lwt.wakeup_paused(); 
    match Lwt.poll t with 
    | Some x -> x 
    | None -> next_tick (fun() -> run t) 

此功能僅運行unit Lwt.t類型的線程但這是一個程序的主殼體。可以使用Lwt_mvar.t進行通信來計算任意值。

也可以擴展此示例以支持各種掛鉤,如原始Lwt_main.run實現中那樣。

相關問題