Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Immutable List Gem (KLab ALM版)

2,719 views

Published on

関数型スタイルでのクイックソートを高速化した話(Ruby)です。KLab ALM 2014/07/29 で発表しました。

Published in: Technology
  • Be the first to comment

Immutable List Gem (KLab ALM版)

  1. 1. Immutable List Gem 2014/07/29 KLab 社内勉強会 ALM 細田 翔 (@gam0022)
  2. 2. 自己紹介 細田 翔 筑波大学情報学群情報科学類 B4 - 非数値処理アルゴリズム研究室 15卒 KLab内定者 Twitter: @gam0022 http://gam0022.net/ 2
  3. 3. 話す内容 関数型スタイルでのクイックソートを高速化した話(Ruby) 3
  4. 4. クイックソート 念のためにおさらい クイックソートの基本的な考え - データを軸要素(ピボット)より 大きい要素・小さい要素で分割 することを再帰的に繰り返して ソートを行なう 4 http://www.ics.kagoshima-u.ac.jp/~fuchida/edu/algorithm/sort-algorithm/quick-sort.html
  5. 5. Rubyでクイックソート 手続き型スタイルで実装した場合 特徴 1. コードが長い
 (tempなどの変数が必要) 2. 昇順降順の切り替えに2箇所の変更 3. 動作が追いにくい 5
  6. 6. OCamlでクイックソート OCaml (関数型言語)による実装 特徴 1. 5行で書ける! 2. 昇順降順の切り替えは1箇所の変更 3. 動作が追いやすい 6
  7. 7. Ruby vs OCaml Ruby vs OCaml - OCaml の圧倒的な勝利 Ruby でも OCaml のよう なクイックソートを書きたい! 7 Ruby OCaml 行数 29 5 昇順降順の 変更箇所 2 1 可読性 △ ○
  8. 8. Ruby でクイックソート その2 OCaml Ruby 左: OCamlの5行のコードを List.partition を使わないで再実装 右: 左のコードを Ruby に移植したコード Ruby でも関数型スタイルにプログラミングできた! 8
  9. 9. だが待って欲しい!
  10. 10. Ruby でクイックソートその2 このコードは確かに動作する 問題点 - Array#+ や Array#drop は非破 壊的メソッド - Array のインスタンスを大量に生成 - Array を何度もコピー 10
  11. 11. 処理コストが大きい!
  12. 12. データ構造を見直す 関数型スタイルのプログラミングには、Array(配列)は適さない データ構造から見なおしてみる (Immutable) Singly Linked List が最適 - イミュータブルな単方向連結リスト - OCaml や Lisp の List にも使われる 12
  13. 13. Immutable Singly Linked List を実装 普通に Ruby で実装してもネタとして面白くない Array は組み込みクラスであり、C言語で実装されているので、 普通にRubyで実装してもパフォーマンス的にも勝ち目がない 「C拡張」として、実装しよう! 13
  14. 14. Ruby の C拡張 C拡張 - C言語で書いたコードをリンクして Ruby から利用する仕組み 部分的な処理の高速化・ラッパーライブラリなどに使われる 例:C拡張を利用した gem - スクレイピングライブラリの nokogiri - SQlite3 のラッパーライブラリの sqlite3 14
  15. 15. ImmutableList の実装 クラス名は ImmutableList struct immutable_list の定義 (Cの構造体をラップ) 15
  16. 16. ImmutableList の実装 OCaml を意識したメソッドを実装 - cons - head, tail - rev_append, rev, append - length - nth - inspect 16
  17. 17. ImmutableList の実装 cons (先頭への要素追加) の定義 17
  18. 18. ImmutableList の実装 全部で200行くらいで実装できた 罠が多くて苦労した - 明示的にオブジェクトをmarkしないと GC で勝手にオブジェ クトが開放されて SEGV が発生したりとハマりどころが多い - Ruby 処理系の勉強にはすごくなった 18
  19. 19. Ruby でクイックソート その3 ImmutableList を使用して再実装 19
  20. 20. Ruby でクイックソート 考察 全く同じ処理 クラスを置き換えただけ 性能に違いが出るか? 20 Array ImmutableList Array ImmutableList first head drop(1) tail [i]+a a.cons(i)
  21. 21. ベンチマーク データの長さn と 処理時間(CPU時間) の関係を調査 ソートデータ: 重複のないランダムなデータを使用 最新の Ruby 2.1.2 を使用 21
  22. 22. 結果 22 リストの長さのクイックソートの実行時間 実行時間[sec] 0 0.1 0.2 0.3 0.4 リストの長さ[個] 0 2000 4000 6000 8000 Array ImmutableList リストの長さに比例して、ImmutableList が高速になる 最大で4.3倍の高速化!
  23. 23. まとめ 処理によっては、再帰を用いた関数型スタイルでプログラミン グすることで、シンプルに実装できる場合がある パフォーマンス的には、Ruby の Array は関数型スタイルには 適していない C拡張として実装した ImmutableList によって、関数型スタ イルでのクイックソートを高速化することができた! 23
  24. 24. RubyGems に公開中 RubyGems は Ruby ライブラリの管理システム immutable_list の名前で登録済みなので、コマンド一発で導入可能 24
  25. 25. ご静聴ありがとうございました
  26. 26. おまけ 本当にC拡張で作った意味があったので疑問だったので、Ruby でも同じ機能を持つクラスを実装した ソースコードはC実装の1/3くらいになった(Rubyの生産性す ごい) 次のベンチマークをとった - 先ほどのクイックソート - 単純な連結(append)処理 26
  27. 27. ImmutableListのRuby実装と比較 Ruby で実装した ImmutableList(Ruby) 手続き型スタイルのクイックソート Procedural 27 リストの長さとクイックソートの実行時間 実行時間[sec] 0 0.1 0.2 0.3 0.4 リストの長さ[個] 0 2000 4000 6000 8000 Array ImmutableList ImmutableList(Ruby) Procedural C拡張版の方が少し高速
  28. 28. ImmutableListのRuby実装と比較 連結の回数と実行時間(対数グラフ) 実行時間[sec] 0.01 0.1 1 10 100 連結回数[回] 1000 10000 100000 Array ImmutableList ImmutableList(Ruby) 長さ6のリストをn回連結 28
  29. 29. ImmutableListのRuby実装と比較 C拡張版の方が高速で良かった でも、思ったよりは変わらなくて残念(́・ω・`) 関数型スタイルは手続き型スタイルよりすごく遅い 29
  30. 30. Immutable List が Array より
 メモリの消費が少ない説明
  31. 31. Arrayの連結 C = A+B を行なった時、AとBの内容を全てコピーする 1 2 3 4 5 6 7 8+ A B 1 2 3 4 5 6 7 8 A B 1 2 3 4 5 6 7 8 C
  32. 32. Immutable Singly Linked List の連結 C = A+B を行なった時、Bとの差分だけがコピーされる 1 2 3 4 5 6 7 8+ A B 1 2 3 A 1 2 3 C 4 5 6 7 8 B
  33. 33. head と tail 次の操作は参照を返すだけなので、とても高速 - head: 先頭の要素の取り出し Array#first に対応 - tail: 2番目以降のリストの取り出し Array#drop に対応 33 1 2 3 4 5 6 7 8 tail head

×