我需要以如何使用ocaml-threads编程并行iter函数为例。我的第一个想法是拥有一个与此类似的功能:
let procs = 4 ;;
let rec _part part i lst = match lst with
[] -> ()
| hd::tl ->
let idx = i mod procs in
(* Printf.printf "part idx=%i\n" idx; *)
let accu = part.(idx) in
part.(idx) <- (hd::accu);
_part part (i+1) tl ;;
然后,并行iter可能看起来像这样(这里是基于流程的变体):
let iter f lst = let part = Array.create procs [] in
_part part 0 lst;
let rec _do i =
(* Printf.printf "do idx=%i\n" i; *)
match Unix.fork () with
0 -> (* Code of child *)
if i < procs then
begin
(* Printf.printf "child %i\n" i; *)
List.iter f part.(i)
end
| pid -> (* Code of father *)
(* Printf.printf "father %i\n" i; *)
if i >= procs then ignore (Unix.waitpid [] pid)
else _do (i+1)
in
_do 0 ;;
因为Thread-module的使用有点不同,我将如何使用ocaml的线程模块对其进行编码?
还有另外一个问题,_part()函数必须扫描整个列表以将它们分成n个部分,然后每个部分将通过每个自己的进程(这里)进行管道传输。还是存在一个没有先拆分列表的解决方案吗?
答案 0 :(得分:3)
如果您有一个处理列表的函数,并且您希望独立地在多个列表上运行它,则可以使用该函数和每个列表调用Thread.create
。如果您将列表存储在数组part
中,则:
let threads = Array.map (Thread.create (List.iter f)) part in
Array.iter Thread.join threads
INRIA OCaml线程不是实际线程:在任何给定时间只执行一个线程,这意味着如果您有四个处理器和四个线程,则所有四个线程将使用相同的处理器,而其他三个线程将保持未使用状态。
线程有用的地方在于它们仍然允许异步编程:一些Thread
模块原语可以等待外部资源变得可用。这可以减少您的软件花费在不可用资源上的时间,因为您可以让另一个线程同时执行其他操作。您还可以使用它同时启动多个外部异步进程(例如通过HTTP查询多个Web服务器)。如果您没有很多与资源相关的阻止,这对您没有帮助。
关于列表拆分问题:要访问列表元素,必须遍历所有先前的元素。虽然这种遍历在理论上可以分散在多个线程或进程中,但是通信开销可能会比在一个进程中提前分割事物慢得多。或使用数组。
答案 1 :(得分:2)
回答评论中的问题。答案本身并不适合评论。
OCaml运行时存在锁定。当OCaml线程即将进入
的C函数时,将释放锁定所以你只能使用一个OCaml线程,但是你有时可以让非堆使用的C函数与它并行工作。
例如,请参阅文件ocaml-3.12.0/otherlibs/unix/write.c
memmove (iobuf, &Byte(buf, ofs), numbytes); // if we kept the data in the heap
// the GC might move it from
// under our feet.
enter_blocking_section(); // release lock.
// Another OCaml thread may
// start in parallel of this one now.
ret = write(Int_val(fd), iobuf, numbytes);
leave_blocking_section(); // take lock again to continue
// with Ocaml code.