ブログ更新をtweetしていたら、@camloebaさんに Bufferがあることを教えていただいた。
いつもありがとうございます!
ということで、Bufferを使うように修正してみた。
修正後のプログラム
修正したのはparse関数だけ。let parse element_func_list =
let tags = Stack.create () in
let element_func () =
let item = List.find element_func_list ~f:(fun (element_list, _) ->
Stack.to_list tags = element_list
) in
match item with
Some (_, func) -> Some func
| None -> None in
let in_content = ref false in
let content = Buffer.create 1024 in
let apply_func = ref (fun _ -> ()) in
Pxp_ev_parser.process_entity config entry entmng (fun ev ->
(* let event_string = Pxp_event.string_of_event ev in *)
match ev with
Pxp_types.E_start_tag (name, _, _, _) -> begin
Stack.push tags name;
(* print_endline @@ List.to_string (Stack.to_list tags) ~f:ident; *)
match element_func () with
Some func' -> begin
apply_func := func';
in_content := true
end
| _ -> ()
end
| Pxp_types.E_end_tag (name, _) -> begin
ignore @@ Stack.pop_exn tags;
if !in_content then
begin
!apply_func @@ Buffer.contents content;
Buffer.clear content;
in_content := false;
end;
end
| Pxp_types.E_char_data str -> begin
if !in_content then
Buffer.add_string content str
end
| _ -> ())
このような修正は、動的な型の言語の場合、必要な修正箇所を見逃しやすいが、
OCamlのような静的な型の言語の場合は、コンパイルエラーで検出できるので非常にやりやすい。Emacs+Tuaregでコード書いており、保存と同時にエラーがある行の色が変わるので、修正箇所は一目瞭然。
実行結果
satoshi@xubuntu:~/workspace/ocaml-try/pxp$ time ./parse_wiki > /dev/null real 0m0.093s user 0m0.081s sys 0m0.011s修正前は、
satoshi@xubuntu:~/workspace/ocaml-try/pxp$ time ./parse_wiki > /dev/null real 0m3.361s user 0m3.168s sys 0m0.180sおよそ35倍速くなった!
これなら全く問題なし。
計測していないが、メモリの使用量も、かなり減ったはず。
なお、^による文字列連結に関しては、 Real World OCaml Chapter 3. Lists and Patternsの Performance of String.concat and ^ にも書かれていた。
^ を使うたびに文字列を生成するので、少しずつ文字列を連結して、大きな文字列を作る場合は、非常にパフォーマンスが悪い。

0 件のコメント:
コメントを投稿