我想要实现的是,我自己的List.fold_right
版本或List.fold_left
Event Module
和Thread 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
答案 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时间的例子。