Upgrade to Pro — share decks privately, control downloads, hide ads and more …

第1回 Rust Hands-On

Yuki Toyoda
February 17, 2021
2.4k

第1回 Rust Hands-On

2021/02/17 に、サイバーエージェント社内向けに開催した Rust ハンズオンの資料です。第1回は、Rust の概観を掴んでもらうことを目的にプレゼンテーションを行いました。

Yuki Toyoda

February 17, 2021
Tweet

Transcript

  1. 自己紹介 Yuki Tw: @helloyuki_ • AI 事業本部所属のテックリード。 • Rust 領域における

    Next Experts。 • 外部での活動がこれまではメインだった。
  2. Rust との出会い • 前職: 信用デリバや金利デリバなどのリスク管理計算機を作るエンジニアだった。 • 言語は Java 8 だった(プライシングエンジンまわりは

    C++)。 • 金融では大量のスレッドを使用した計算をする。 • Java でのマルチスレッド計算はかなり熟練した技術者でもバグを仕込みやすい。あと GC 、お前な。 • Rust を紹介(というか惜しみなく絶賛)する Googler の記事に出会う。 • 「こうすれば並行処理で苦労しないのに…」と思っていたアイディアが当時自分の中にあった。 • ぶっちゃけ GC なくなってくれない?安定しないんだけど?とちょっと思ってた。 • Rust は自分の思っていたアイディアを言語レベルでサポートしていることを知る。GC もない。 • この言語すごいなと思ってはじめた。
  3. Rust はどの ような言語 か? • Rust 概要 • 言語の特長 •

    Rust の速さ • GC とメモリ安全 • ゼロコスト抽象化
  4. 2020年のRustの調 査 • Rust は毎年、言語に関するアンケー トを取っている。 • Webバックエンドの利用例が1位。 • 分散システム、組み込みデバイスな

    どが続く。 • 観測範囲では、仮想通貨やブロック チェーンでの利用例も多く感じる。 https://blog.rust-lang.org/2020/04/17/Rust-survey-2019.htmlより引用。 画像はランキングの一部を切り取り。
  5. GC のメリデメ メリット デメリット • メモリ管理を手動でしなくていい 。 • コード上にメモリ管理に関する追 加のノイズがなくなる。

    • 多くのメモリに関する脆弱性は発 生しない。 • など • たとえばMark&SweepならSweep されるまでオブジェクトを解放で きない。 • ときどき一気にメモリが解放され る時間帯が発生し、その間はアプ リケーションが止まる。 • ランタイムを肥大化させやすい。 • など
  6. Rust の領域と GC • Rust が担当する領域は、組み込みのファームウェアや OS になる。 • 計算資源が限られた環境で動くという前提がある。

    • この制約下では、下記は困る。 • 言語自体がメモリを多く消費する設計になっている。 • ランタイムが大きい。 • フル GC などでアプリケーションを止められる。
  7. メモリの手動管理は… • GC は選択肢にのぼらなくなるが、メモリの手動管理をする必要がある。 • 速度は段違いになる。 • メモリの手動管理はUB (Undefined Behaviour)

    を生みやすくなる。 • C/C++ 製のアプリケーションではよく UB 起因の脆弱性が報告される。 ※ サニタイザなどのツールの力を借りることはもちろんできる。 ※ C++11からはムーブセマンティクスが導入されたが、あれはあれでいくつか課題があった。
  8. 事例: Chromium Project • Chromium は C++ 製。 • メモリ関係の脆弱性が70%近くを

    占める。 • ↓によるとコストは高い評価だが Rust も検討のテーブルに入ってい る。 どちらの画像も https://www.chromium.org/Home/chromium-security/memory-safety より引用
  9. Rustの場合はどうしたか • Rust は GC を採用していない。 • Rust は「メモリ安全はコンパイラが検査する」で解決した。 •

    「所有権」「ライフタイム」の仕組みで、メモリ安全でないコードはコンパイル時に弾く。 • 「コンパイラが厳しい」理由はここにある。 • この仕組みの裏側には型理論の研究成果が含まれている。 • こうしたメモリ安全・並行処理安全の仕組みは、第2回で詳しく説明する予定。 • 速度面と安全性のトレードオフを打破した。
  10. ゼロコスト抽象化とは • コードの抽象化を行ったとしても、追加のオーバーヘッドが発生しないこと。 • メモリ使用量が増加しない。 • 実行速度が低下しない。 • Rust における「抽象化」

    • 多相性: ジェネリクス(パラメトリック多相)やトレイト(アドホック多相)。 • 高階関数: filter や map、あるいはクロージャを引数にとる関数。 • Future: 並行処理の抽象機構。
  11. 他のプログラミング言語では • 例: ジェネリクスを使用すると、動的ディスパッチによるオーバーヘッドが発生する。 • 実行時に関数の抽象と実装の紐付けを行う言語がほとんど。 • この方式を採用すると、紐付けを定義するテーブルの分のメモリ使用量が増える。 • 関数を呼び出す度にテーブルから探すので、その分のオーバーヘッドも増える。

    • 例: for ループと for 内包表記とラムダは、全部実行速度が違う。 • 同じことを実現したいのに、採る手法によって実行速度が変わること全般を指す。 • いい例は Py …(おっと誰かが来たようだ。 • 全部実行速度が違うので、プログラマは適切な手法を知っていないとすぐオーバーヘッドが発生。
  12. ゼロコスト抽象化のよさ • ゼロコスト抽象化のおかげで、下記のことは考慮しなくて良くなる。 • 抽象化すべき箇所で、実行速度を気にしてやめる。 • XXX という手法は速度が落ちる。YYY という手法を使うべき。 •

    ZZZ を採用すると、メモリ使用量が上がるから、AAA というハックをすべき。 • こういったワークアラウンドこそ、本当の意味での学習コストではないか? • 正直本質的ではない。 • 我々はコンピュータや実装と真正面から向き合いたい。 • ゼロコスト抽象化がないと C++ の代替は目指せないので、とても重要。
  13. 動的/静的ディスパッチ • 関数等の紐付けが実行時に解決されること。 • 動的型付き言語の大半。ダックタイピングみたいな。 • Java の implements X

    をしたとき、など。 • 都度解決する&参照のためにテーブルを探すので、遅い。 • ⇔静的ディスパッチ • 静的ディスパッチはコンパイル時に関数等の紐付けを解決すること。
  14. 制御構文 • if, for あたりは他の言語と同じように使える。 • Pattern Matching と呼ばれる switch

    文の強力版が使える。 • 制御構文はすべて式(expression)な点に注意する。
  15. エラーハンドリング • 実用上は • プログラム自体の想定しないバグであれば panic しておく。 • 想定内のエラーであれば Result

    でハンドリングする。 • Java とのアナロジーで考えるなら(Rust には例外機構はないことに注意)、 • panic は非検査例外(RuntimeException) • Result は検査例外(Exception)
  16. unsafe • 生ポインタを参照できるようになる。 • 標準ライブラリの unsafe 関数を使用できる。 • unsafe キーワード

    • unsafe fn • unsafe trait • unsafe ブロック • unsafe ブロック内はコンパイラが安全性保証をしない。 • Rust は C/C++ の外部関数を呼び出す機能も持つ。
  17. エディタどうする? • ご自由にどうぞ。 • 黄金の組み合わせは VSCode に rust-analyzer をインストールすること。 •

    今後のハンズオンもそれで行うので、使ってもらえるとトラブルシュートが早くなります。 • rust-analyzer 自体は Vim や Emacs でも使える。 • また、IntelliJ に Rust プラグインがあります。