为什么Array.map比尾递归映射更快(相当)?

时间:2014-02-10 11:54:59

标签: ocaml

我像这样编写map_tail的尾递归版本:

let map_tail f l =
  let rec map acc = function
    | [] -> List.rev acc
    | hd::tl -> map (f hd :: acc) tl
  in 
  map [] l

然后是基于map_by_array的数组:

let map_by_array f l =
  Array.of_list l |> Array.map f |> Array.to_list

以下是基准代码

let ran_list n =
  Random.self_init();
  let rec generate acc i =
    if i = n then acc
    else generate (Random.int 5::acc) (i+1)
  in 
  generate [] 0

let _ =
  let l = ran_list 10000000 in
  let f x = x+1 in
  let t1 = Sys.time() in
  let l1 = map_tail f l in
  let t2 = Sys.time() in
  let l2 = map_by_array f l in
  let t3 = Sys.time() in
  Printf.printf "map_tail: %f sec\nmap_by_array: %f sec\n" (t3-.t2) (t2-.t1)

我发现基于数组的地图速度更快,这让我感到很惊讶。

map_tail中,它会遍历列表twicemap_by_array遍历列表three times,为什么它仍然更快?

1 个答案:

答案 0 :(得分:3)

这可能取决于列表的大小。

在大小为N的长列表中,map_tail将执行 2 * N 分配(地图中为N,然后List.rev为N),而map_by_array }将执行 N + 2 分配(Array.of_list为1,Array.map为1,Array.to_list为N,实际上可以优化为仅一个分配也是)。

由于分配可能是此代码中最昂贵的操作,因此这种差异应该可以解释性能的差异。