2020年3月31日火曜日

インメモリデータベースの開発言語にRustを選んだ理由。Why we chose Rust as our in-memory database development language.

https://www.forcia.com/blog/001167.html
シェアしました。

QiitaのRust Advent Calendar 2018 4日目の記事です。
技術本部の松本です。フォルシアではインメモリデータベースをRustで開発しています。本記事では、なぜRustを選んだかをご説明します。

速度

Rustは2015年に1.0がリリースされた比較的新しいプログラミング言語であり、「速度、安全性、並行性」をゴールとしています。
言語の選定にあたっては、動作速度が重要視されました。Computer Language Benchmarks Game(ベンチマーク結果を公開しているサイト)によれば、RustはJavaやGoより高速で、C++並の速度が出ると言われています。実際に我々が検証した際も、RustはGoよりは高速で、Javaと異なりGCが無いため、Rustの方が好ましいという結果になりました。

ガベージコレクション(GC)が無い

Rustでは所有権の概念を取り入れることで、いつメモリ上からオブジェクトが解放されるか、管理しています。そのためGCが必要なく、GCによるプログラムの停止を避けることが出来ます。技術検証時にJava実装を検討しましたが、GCが走るタイミングでレスポンスに時間がかかることがあり、安定して高速なレスポンスを返すインメモリデータベースの用途上、Rustに軍配が上がりました。

静的ディスパッチによるゼロコスト抽象化

Rustがなぜ速いのかという文脈で「ゼロコスト抽象化」というキーワードに言及される事が多いですが、少し噛み砕いて説明したいと思います。
Rustではジェネリクス(generics)とトレイト(trait)によって多相性(Polymorphism)をサポートしています。ジェネリック関数は同じ名前の関数に異なる型を渡すことができます。下記に例を示します。
  1. use std::fmt::Debug;
  2. fn main() {
  3. fn print_debug(x: T) {
  4. println! {"{:?}", x};
  5. }
  6. print_debug(1u8);
  7. print_debug("&str");
  8. #[derive(Debug)]
  9. struct Point {
  10. x: i32,
  11. y: i32,
  12. }
  13. let origin = Point { x: 0, y: 0 };
  14. print_debug(origin);
  15. }
ジェネリック関数(上記例ではprint_debug)を用いた場合、コンパイル時点で引数の型が全て明らかになっている(u8, &str, Point)ため、それぞれの型専用の関数が作成されます。 実行時に型から関数への割当関係を解決する動的ディスパッチを行う場合は実行時にその分のコストが掛かりますが、Rustはコンパイル時に解決してしまう静的ディスパッチを使用するため、実行時にはゼロオーバーヘッドで関数を対応する呼び出す事ができます。

開発効率

また、開発効率の面も考慮事項でした。Rustは新しい言語ではあるものの、他の言語以上に効率良く開発できる環境が整っています。標準的なツールセットがあることや、テストが標準ライブラリに含まれていることはC++よりも好ましい部分です。

0 コメント:

コメントを投稿