使用主题和频道加速List.fold

时间:2017-03-17 11:37:11

标签: multithreading list ocaml channel

我想要实现的是,我自己的List.fold_right版本或List.fold_left Event ModuleThread Module,以加快这一过程。

(我知道Ocaml不支持并行多线程,但我在这里是为了概念)

我的尝试:(虽然我不确定我是否赢得了额外的时间)

open Thread
open Event
let rec tapply f start = function
  | [] -> start
  | h::t -> let c = new_channel () in
            let _ = create (fun _ -> sync (send c (f h (tapply f start t)))) () 
            in sync (receive c)

致电tapply

#tapply ( * ) 1 [1;2;3;4];; - : int = 24

1 个答案:

答案 0 :(得分:3)

在一般情况下,并行折叠函数是不可能的,因为每个中间值都依赖于所有先前的值。例如,请参阅Cipher Block Chaining。如果满足某些附加条件,则可以进行并行化。

示例1:如果可以将每个列表元素视为一个函数(例如:组操作),那么您可以使用分而治之的方法来利用函数的关联性,其中您首先计算由列表表示的函数,然后将其应用于初始元素。

示例2:如果函数是可交换的并且您使用的是reduce而不是折叠操作,则可以将列表拆分为子列表并分发子列表的工作,例如:

open Batteries

let par_reduce n f l =
  (* worker thread *)
  let worker (ch, l) =
    List.reduce f l |> Event.(sync % send ch) in
  (* split [l] in [n] sublists *)
  let k = max (List.length l / n) 1 in
  let sublists = List.ntake k l in
  (* create [n] worker threads *)
  List.map (fun sublist ->
    let ch = Event.new_channel () in
    let _ = Thread.create worker (ch, sublist) in
    ch) sublists
  (* collect results *)
  |> List.map Event.(sync % receive)
  (* and combine those into the final result *)
  |> List.reduce f

let factorial n =
  par_reduce 4 Num.mult_num (List.init n (fun k -> Num.of_int (k+1)))

let () =
  Printf.printf "%s\n" Num.(to_string @@ factorial 1000)

注1:这使用“包含电池”库来实现一些便利功能。

注意2:有更快的方法来计算大因子 - 实际上,代码甚至没有均匀地分割工作 - 这只是一个实际使用一些CPU时间的例子。