Comment detail

分散関数呼び出し (Nested Flatten)
JoCaml は OCaml に並行プログラミングの概念の一つである join calculus のサポートを組み込んだ言語です。
並行プログラミングと分散プログラミングがサポートされています。

server.ml を動かした状態で client.ml を動かすことで、サーバ側に定義されている price_string 関数が 10000 回実行されます。

サーバ:
 Mac OS X 10.5 PPC G5/1.8GHz mem:1GB
クライアント:
 FreeBSD 6.2R Pen3/550MHz mem:256MB

という環境でテストしました。
まずインタプリタで、

 server% jocaml server.ml 10000
 listening address 10.0.1.5
 listening port 10000

 client% time jocaml client.ml 10.0.1.5 10000
 jocaml client.ml 10.0.1.5 10000  12.28s user 1.09s system 69% cpu 19.178 total

jocamlopt でネイティブコンパイルしたもので、

 server% ./server 10000

 client% time ./client 10.0.1.5 10000
 ./client 10.0.1.5 10000  4.84s user 1.17s system 60% cpu 9.930 total

といった感じでした。
実行される関数はサーバ側に定義されているので、実際の実行はサーバ側でされています。
それと、JoCaml では for 文が並行実行されるので、client.ml での price_string の呼び出しはおそらく直列には動いていません。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
(* server.ml *)

def price_string(value, discount) =
   let comma_sep () num =
      let str  = Printf.sprintf "%d" num in
      let len  = String.length str in
      let rec s_to_l r i =
         if i >= len then r
         else
            s_to_l (str.[i] :: r) (i + 1)
      in
      let str', _ =
         List.fold_left begin fun (s, i) ch ->
            match i with
            | 3 -> (ch :: ',' :: s, 0)
            | i -> (ch :: s, (i + 1))
         end ([], 0) (s_to_l [] 0)
      in
      List.fold_left begin fun acc ch ->
         acc ^ (String.make 1 ch)
      end "" str'
   in
   let new_value = value * (100 - discount) / 100 in
   let msg =
      Printf.sprintf "販売価格 %a円 (定価%a円から%d%%引き)"
                     comma_sep new_value comma_sep value discount
   in
   reply msg to price_string

let main () =
   match Sys.argv with
   | [|_; listen_port|] -> begin
        let addr = Join.Site.get_local_addr () in
        let addr_str = Unix.string_of_inet_addr addr in
        let sock = Unix.ADDR_INET (addr, int_of_string listen_port) in
        List.iter print_endline
           ["listening address " ^ addr_str;
            "listening port " ^ listen_port];
        Join.Ns.register Join.Ns.here "price_string" price_string;
        Join.Site.listen sock;
        at_exit Join.exit_hook
     end
   | _ ->
        print_endline "usage: command listen_port"

let () = if not !Sys.interactive then main ()


(* client.ml *)

let main () =
   match Sys.argv with
   | [|_; server_addr; server_port|] ->
        let addr = Unix.inet_addr_of_string server_addr in
        let sock = Unix.ADDR_INET (addr, (int_of_string server_port)) in
        let namespace = Join.Ns.there sock in
        let price_string : int * int -> string =
           Join.Ns.lookup namespace "price_string"
        in
        for i = 0 to 10000 do
           ignore (price_string (2000, 20))
        done;
        print_endline (price_string (2000, 20))
   | _ ->
        print_endline "usage: command server_address server_port"

let () = if not !Sys.interactive then main ()
> それと、JoCaml では for 文が並行実行されるので、client.ml での price_string の呼び出しはおそらく直列には動いていません。

うっかりしてました。
この話はプロセスコンテキストでは正しいですが、投稿したコードの例では for は式コンテキストで使われているので、この場合は直列に動いているはずです。

この例で並行に動かすなら for の前に spawn を追加すれば良いと思います。(diff 参照)
その場合 for の内部はプロセスコンテキストになるので、price_string をプロセス扱いにするために空のプロセス 0 を付け足しています。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
--- client.ml.orig    2007-11-24 20:24:55.000000000 +0900
+++ client.ml    2007-11-24 20:31:51.000000000 +0900
@@ -9,8 +9,8 @@
         let price_string : int * int -> string =
            Join.Ns.lookup namespace "price_string"
         in
-        for i = 0 to 10000 do
-           ignore (price_string (2000, 20))
+        spawn for i = 0 to 10000 do
+           (ignore (price_string (2000, 20)); 0)
         done;
         print_endline (price_string (2000, 20))
    | _ ->

Index

Feed

Other

Link

Pathtraq

loading...