Mailing list for all users of the OCaml language and system.
 help / color / mirror / Atom feed
From: Thomas Fischbacher <tf@functionality.de>
To: Jon Harrop <jon@ffconsultancy.com>
Cc: caml-list@inria.fr
Subject: Re: [Caml-list] Faking concurrency using Unix forks and pipes
Date: Wed, 30 May 2007 10:52:56 +0100	[thread overview]
Message-ID: <465D4978.8010904@functionality.de> (raw)
In-Reply-To: <200705300442.59906.jon@ffconsultancy.com>

Jon Harrop wrote:

> Has anyone implemented a parallel map function in OCaml using Unix forks, 
> pipes and maybe marshalling?
> 
> This seems like an easy way to get concurrency in OCaml...

That is indeed an exercise I like to pose to my PhD students.
(Of course, the question whether this really makes that much
sense is a different issue...)


Here is my own suggestion how to do it:


let compute_uniform_workload_forked
     ?(bailout=
	(fun str ->
	   let () = Printf.fprintf stderr "AIEE! %s\n%!" str in
	     exit 1))
     ~fun_combine
     v_work =
   let bailout s dummy = let _ = bailout s in dummy in
     (* Note that we use the "bailout" function in two different places 
where it expects
        different return types. Hence, we have to bend over backwards to 
get the type
        system to accept what we actually want to do...
     *)
   let nr_processes = Array.length v_work in
   let rec setup_childs nr_process child_info =
     if nr_process = nr_processes
     then List.rev child_info (* This ensures we get the data in proper 
order. *)
     else
       let (fd_read,fd_write) = Unix.socketpair Unix.PF_UNIX 
Unix.SOCK_STREAM 0 in
       let pid = Unix.fork () in
	if pid == (-1) (* fork failure *)
	then
	  bailout "fork() failure!" child_info
	else
	  if pid == 0 (* We are the child - compute our share and exit *)
	then
	  let () = Unix.close fd_read in
	  let s_write = Unix.out_channel_of_descr fd_write in
	  let result = v_work.(nr_process) () in
	  let () = Marshal.to_channel s_write result [] in
	    exit 0
	else
	  (* We are the parent *)
	  let () = Unix.close fd_write in
	  let s_read = Unix.in_channel_of_descr fd_read in
	    setup_childs (1+nr_process) ((s_read,pid)::child_info)
   in
   let all_childs_info = setup_childs 1 [] in
     (* Note that it is important that we start counting at 1 here, as 
the parent will do
        chunk #0!
     *)
   let result_chunk0 = v_work.(0) () in
     (* Note that we just do assume that all pieces of the computation 
take the same time.
        We are not trying to be overly sophisticated, fetching data from 
the fastest
        child first. Also, if we wanted a more powerful tool to compute 
with forked processes,
        we might want to divide the big task in a more fine-grained way 
and hand out sub-tasks
        to processes through a scheduler that takes care of when which 
process finishes
        which sub-task. For now, this is overkill.
     *)
   let rec collect_child_results have child_info_todo =
     match child_info_todo with
       | [] -> have
       | ((s_read,pid)::child_info_todo_next) ->
	  let contrib = Marshal.from_channel s_read in
	  let (returned_pid,status) = Unix.waitpid [] pid in
	    if status <> Unix.WEXITED 0
	    then
	      bailout "Child failure!\n%!" have
	    else
	      collect_child_results
		(fun_combine contrib have)
		child_info_todo_next
   in collect_child_results result_chunk0 all_childs_info
;;


(* ---
(* === Example === *)
let sum_of_inverse_squares =
   compute_uniform_workload_forked
     ~fun_combine:(fun a b -> a+.b)
     (let nr_processes=4 in
      let ranges=split_range nr_processes 1 100000 in
      let work subrange_start subrange_end =
        let () = Printf.printf "PID: %d SUB-RANGE %d - %d\n%!"
	 (Unix.getpid()) subrange_start subrange_end
        in
        let rec walk n sum =
	 if n = subrange_end then sum
	 else walk (1+n) (let fn = float_of_int n in sum +. 1.0/.(fn*.fn))
        in walk subrange_start 0.0
      in
        (Array.init nr_processes
	  (fun n ->
	     let (r_s,r_e) = ranges.(n) in
	       fun () -> work r_s r_e)))
;;

(* This gives: 1.64492406679822967
    The full sum would be pi^2/6 = 1.64493406684822641
*)
--- *)

-- 
best regards,
Thomas Fischbacher
tf@functionality.de


  parent reply	other threads:[~2007-05-30  9:52 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-05-30  3:42 Jon Harrop
2007-05-30  4:10 ` [Caml-list] " Erik de Castro Lopo
2007-05-30  4:12 ` Jonathan Bryant
2007-05-30  9:45   ` Benedikt Grundmann
2007-05-30  7:02 ` Oliver Bandel
2007-05-30  7:31   ` Jon Harrop
2007-05-30 16:22     ` David Teller
2007-05-30  7:34   ` Loup Vaillant
2007-05-30  8:02     ` Jon Harrop
2007-05-30  8:13       ` Erik de Castro Lopo
2007-05-30  8:30         ` Loup Vaillant
2007-05-30  8:32           ` Loup Vaillant
2007-05-30  8:50             ` Jon Harrop
2007-05-30 12:13               ` Richard Jones
2007-05-30  8:54         ` Jon Harrop
2007-05-30  9:56           ` Mattias Engdegård
2007-05-30 12:15           ` Richard Jones
2007-05-30 17:46           ` Pablo Polvorin
2007-05-30 19:14           ` Erik de Castro Lopo
2007-05-30  7:13 ` Florian Hars
2007-05-30 11:31   ` Gerd Stolpmann
2007-05-30  8:40 ` Luc Maranget
2007-05-30  9:10   ` Erik de Castro Lopo
2007-05-30  9:25     ` Erik de Castro Lopo
2007-05-30  9:25       ` Jon Harrop
2007-05-30  9:41         ` Joel Reymont
2007-05-30 16:05         ` David Teller
2007-05-30  9:21   ` Joel Reymont
2007-05-30 16:10   ` David Teller
2007-05-30  9:52 ` Thomas Fischbacher [this message]
2007-05-30 12:03 ` Richard Jones
2007-05-30 16:03 ` Granicz Adam
2007-05-30 22:09   ` Jon Harrop
     [not found] <5F7D2956-2B0A-465A-8AC2-06D7EDC457F9@valdosta.edu>
2007-05-30 19:44 ` Fwd: " Jonathan Bryant
2007-05-30 19:57   ` Erik de Castro Lopo
2007-05-30 20:05     ` Jonathan Bryant
2007-05-30 22:08       ` Jon Harrop

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=465D4978.8010904@functionality.de \
    --to=tf@functionality.de \
    --cc=caml-list@inria.fr \
    --cc=jon@ffconsultancy.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox