Let 是否利用数据依赖性来增加并行性

Does Lwt utilise data dependencies to increase paralleism

我试图通过几个例子来弄清楚 lwt 具体在做什么:

如果我有:

let%lwt x = f () in
let%lwt y = g () in
return ()

这个 运行 f 然后 g,或者因为 y 不依赖 x 会 运行 两者并行吗?

那个特定的例子 运行s f ()g () 按顺序,即 g () 直到承诺 return 之后才开始 return =14=]已解决。

看到这个的方法是,当看到

let%lwt x = e in
e'

实现 e' 成为回调的 body,只有当 x 可用时才会 运行。所以,在题中的代码中,Lwt首先看到:

(* Do this first. *)
let%lwt x = f () in

(* Do this once is available. *)
let%lwt y = g () in
return ()

并且,一旦 x 可用,就剩下

(* Do this next. *)
let%lwt y = g () in

(* Do this once y is available. *)
return ()

为了避免这种序列化,首先调用f ()g (),没有任何干预let%lwt,将变量绑定到承诺x'y'这些函数 return,并等待承诺:

let x' = f () in
let y' = g () in
let%lwt x = x' in
let%lwt y = y' in
return ()

(回答标题,Lwt 不使用数据依赖。我不认为图书馆可以访问这种数据依赖信息)。

在您的代码中,不,因为您将 Lwt.t 用作 monad,而不是应用程序。

单子

您可能已经熟悉异步 IO 以及函数 Lwt.bind : 'a Lwt.t -> ('a -> 'b Lwt.t) -> 'b Lwt.tLwt.return : 'a -> 'a Lwt.t。不过,为了以防万一,我将简要回顾一下:

  • Lwt.bind promise callback 等待 promise,并根据结果调用 callback,取回另一个承诺。
  • Lwt.return data 创建一个解析为 data.
  • 的承诺

monad 是一种泛型类型 'a t,它具有某些功能 bind : 'a t -> ('a -> 'b t) -> 'b t 和某些功能 return : 'a -> 'a t。 (这些函数也必须遵循一定的规律,但我跑题了。)显然,类型 'a Lwt.t 与函数 Lwt.bindLwt.return 构成了一个 monad。

Monad 是一种常见的函数式编程模式,当人们想要表示某种 "effect" 或 "computation," 时,在这种情况下是异步 IO。 Monad 之所以强大,是因为 bind 函数让后面的计算依赖于前面的计算结果。如果 m : 'a t 表示导致 'a 的某些计算,并且 f : 'a -> 'b t 是使用 'a 执行导致 'b 的计算的函数,则bind m f 使得 f 依赖于 m.

的结果

Lwt.bind promise callback的情况下,callback取决于promise的结果。 callback 中的代码不能 运行 直到 promise 被解析。

写的时候

let%lwt x = f () in
let%lwt y = g () in
return ()

你真的在写Lwt.bind (f ()) (fun x -> Lwt.bind (g ()) (fun y -> return ()))。因为 g () 在回调中,所以在 f () 解决之前它不是 运行。

应用程序

与 monad 相关的函数式编程模式是 applicative。应用程序是一个泛型类型 'a t,具有函数 map : ('a -> 'b) -> 'a t -> 'b t、函数 return : 'a -> 'a t 和函数 both : 'a t * 'b t -> ('a * 'b) t。然而,与 monad 不同的是,applicatives 不需要 bind : 'a t -> ('a -> 'b t) -> 'b t,这意味着单独使用 applicatives,以后的计算不能依赖于以前的计算。所有 monad 都是应用程序,但并非所有应用程序都是 monad。

因为 g () 不依赖于 f () 的结果,您的代码可以重写为使用 both:

let (let*) = bind
let (and*) = both

let* x = f ()
and* y = g () in
return ()

此代码转换为 bind (fun (x, y) -> return ()) (both (f ()) (g ()))f ()g () 出现在 bind 的回调之外,这意味着它们立即 运行 并且可以并行等待。 bothf ()g () 合并为一个承诺。

(let*)(and*) 运算符是 OCaml 4.08 的新增功能。如果你使用的是较早版本的OCaml,直接写翻译即可。