运行 OCaml 中链式函数和函数列表之间的时间差
Run time difference between chained functions and a list of functions in OCaml
为了注册稍后要调用的单元函数,我使用 (unit -> unit) ref
将函数链接在一起想出了这个解决方案:
let callbacks = ref @@ fun () -> ()
let add_callback f =
let old_callbacks = !callbacks in
callbacks := (fun () -> f (); old_callbacks ())
(* ... call add_callback many times ... *)
(* eventually, run all the callbacks I stacked: *)
!callbacks ()
我想知道它与使用一堆函数的其他解决方案相比如何 (unit -> unit) list ref
:
let callbacks = ref []
let add_callback f =
callbacks := f :: !callbacks
(* ... call add_callback many times ... *)
(* eventually, run all the callbacks I stacked: *)
List.iter (fun f -> f ()) !callbacks
它们在内存中的表示方式是否存在差异?
如果我要注册大量函数,哪种解决方案在内存和拆栈时间方面最好?对于这2个标准,有没有更好的解决方案?
在这两种情况下,您都有一个函数列表。在第一种情况下,列表的节点是函数闭包。在第二种情况下,它们是 cons 元素。我不知道 OCaml 中闭包表示的来龙去脉,但我猜闭包比 cons 元素大(它需要 3 个内存槽用于 header、car 和 cdr(使用旧学校术语))。
当调用时,两种情况都会获取指向下一个函数的指针并调用它。在第一种情况下,指针将从闭包的环境(变量绑定)中获取。在第二种情况下,它将从 cons 中获取。我怀疑访问环境的效率与访问单元格的效率大致相同。即,代码可以使用固定偏移量而不是符号查找。
这些只是猜测。编写两种不同的方法并进行比较实际上会很有趣(也很有趣)。
为了注册稍后要调用的单元函数,我使用 (unit -> unit) ref
将函数链接在一起想出了这个解决方案:
let callbacks = ref @@ fun () -> ()
let add_callback f =
let old_callbacks = !callbacks in
callbacks := (fun () -> f (); old_callbacks ())
(* ... call add_callback many times ... *)
(* eventually, run all the callbacks I stacked: *)
!callbacks ()
我想知道它与使用一堆函数的其他解决方案相比如何 (unit -> unit) list ref
:
let callbacks = ref []
let add_callback f =
callbacks := f :: !callbacks
(* ... call add_callback many times ... *)
(* eventually, run all the callbacks I stacked: *)
List.iter (fun f -> f ()) !callbacks
它们在内存中的表示方式是否存在差异?
如果我要注册大量函数,哪种解决方案在内存和拆栈时间方面最好?对于这2个标准,有没有更好的解决方案?
在这两种情况下,您都有一个函数列表。在第一种情况下,列表的节点是函数闭包。在第二种情况下,它们是 cons 元素。我不知道 OCaml 中闭包表示的来龙去脉,但我猜闭包比 cons 元素大(它需要 3 个内存槽用于 header、car 和 cdr(使用旧学校术语))。
当调用时,两种情况都会获取指向下一个函数的指针并调用它。在第一种情况下,指针将从闭包的环境(变量绑定)中获取。在第二种情况下,它将从 cons 中获取。我怀疑访问环境的效率与访问单元格的效率大致相同。即,代码可以使用固定偏移量而不是符号查找。
这些只是猜测。编写两种不同的方法并进行比较实际上会很有趣(也很有趣)。