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

第1回 Rust Hands-On

Yuki Toyoda
February 17, 2021
2.2k

第1回 Rust Hands-On

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

Yuki Toyoda

February 17, 2021
Tweet

Transcript

  1. Rust Hands-On
    次の40年のためのプログラミング言語
    第1回

    View Slide

  2. 自己紹介
    Yuki
    Tw: @helloyuki_
    • AI 事業本部所属のテックリード。
    • Rust 領域における Next Experts。
    • 外部での活動がこれまではメインだった。

    View Slide

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

    View Slide

  4. 今日のゴール
    • Rust の解決したかったトレードオフを理解する。
    • Rust のコンパイラが厳格な理由を理解する。
    • どういった言語機能があるかを軽く理解する。
    • 実際に環境構築をして Hello, World! する。

    View Slide

  5. 本日お話し
    すること
    • Rust はどのような言語か?
    • Rust の言語機能
    • Rust を実際に動かしてみよう!

    View Slide

  6. 本日お話し
    すること
    • Rust はどのような言語か?
    • Rust の言語機能
    • Rust を実際に動かしてみよう!

    View Slide

  7. Rust はどの
    ような言語
    か?
    • Rust 概要
    • 言語の特長
    • Rust の速さ
    • GC とメモリ安全
    • ゼロコスト抽象化

    View Slide

  8. Rust に
    どんなイメージがありますか?
    アンケート!

    View Slide

  9. Rust 概要

    View Slide

  10. どういう言語なのか?
    • 2015年にリリースされた新しい言語。
    • 一言で言うなら「システムプログラミング言語である」。

    View Slide

  11. システムプログラミング言語
    • 担当領域が低レイヤーであるということ。
    • OS、組み込み機器のファームウェア
    • コンパイラ、VM
    • 各種ミドルウェア
    • ブラウザ

    View Slide

  12. しかし…
    • 言語設計が、モダンな言語機能の全部のせみたいなところがある。
    • 特徴的な言語機能については後ほど解説します。
    • 高級言語並みに表現力が豊かで快適にプログラミングできる。
    • アンケートでは、Web バックエンドへの利用事例が実は多い。

    View Slide

  13. 2020年のRustの調

    • Rust は毎年、言語に関するアンケー
    トを取っている。
    • Webバックエンドの利用例が1位。
    • 分散システム、組み込みデバイスな
    どが続く。
    • 観測範囲では、仮想通貨やブロック
    チェーンでの利用例も多く感じる。
    https://blog.rust-lang.org/2020/04/17/Rust-survey-2019.htmlより引用。
    画像はランキングの一部を切り取り。

    View Slide

  14. 言語のカテゴライズ
    • 静的型付き言語。
    • 型クラス指向あるいはムーブセマンティクス指向。
    • マルチパラダイムプログラミング言語(Scala などが該当する)。
    • 書き味は普通の命令型プログラミング言語(C や Java)。
    • 関数型プログラミング言語ではない。

    View Slide

  15. 言語の特長
    • 非常に実行速度が速く、パフォーマンスが安定的である。
    • GC はないが、メモリ安全・並行処理安全である。
    • メモリ安全: ダングリングポインタ、ヌルポインタなどが発生しない。
    • 並行処理安全: データ競合が発生しない。
    • 速度確保のために実装を歪める必要がない。

    View Slide

  16. 言語の特長
    • 非常に実行速度が速く、パフォーマンスが安定的である。
    • GC はないが、メモリ安全・並行処理安全である。
    • メモリ安全: ダングリングポインタ、ヌルポインタなどが発生しない。
    • 並行処理安全: データ競合が発生しない。
    • 速度確保のために実装を歪める必要がない。

    View Slide

  17. Rust の速さ
    ベンチマークゲームズを参考にして知る

    View Slide

  18. C, Go, Java, Node.js, PHP, Python3, Swift

    実行速度の速い順に並べ替えてみてください!
    クイズ

    View Slide

  19. Benchmark Games
    • 今回参考にするサイトは Benchmark Games というサイト。
    • https://benchmarksgame-team.pages.debian.net/benchmarksgame/index.html
    • ここでいう速さとは、純粋にコード自体の実行時間のことを指している。

    View Slide

  20. Rust の速さはいかほど?
    • Go や Java よりもさらに速い。
    • C/C++ と並ぶかさらに速い。

    View Slide

  21. Rust の速さはいかほど?
    • Go や Java よりもさらに速い。
    • C/C++ と並ぶかさらに速い。

    View Slide

  22. Rust の速さはいかほど?
    • Go や Java よりもさらに速い。
    • C/C++ と並ぶかさらに速い。

    View Slide

  23. なぜ速いのか?
    • 直接機械語にコンパイルされるから。
    • ランタイムがないから。
    • GC がないから。
    • …など。

    View Slide

  24. その他語られる話として
    • Rust には GC がない。
    • このおかげで、メモリ使用量などの予測が立てやすい。
    • GC の気まぐれでパフォーマンスが変わるといった影響を受けにくい。

    View Slide

  25. この節のまとめ
    • Rust は地球上に存在する利用者の多い言語の中では最速の部類に入る。
    • Rust の速さの根本要因は C/C++ と似た話になっている。
    • GC がないこと。
    • VM などを挟まず、機械語に直接コンパイルすること。

    View Slide

  26. 言語の特長
    • 非常に実行速度が速く、パフォーマンスが安定的である。
    • GC はないが、メモリ安全・並行処理安全である。
    • メモリ安全: ダングリングポインタ、ヌルポインタなどが発生しない。
    • 並行処理安全: データ競合が発生しない。
    • 速度確保のために実装を歪める必要がない。

    View Slide

  27. GC とメモリ安全

    View Slide

  28. GC について、知っていることを教
    えて下さい!
    アンケート!

    View Slide

  29. GC のメリデメ
    メリット デメリット
    • メモリ管理を手動でしなくていい

    • コード上にメモリ管理に関する追
    加のノイズがなくなる。
    • 多くのメモリに関する脆弱性は発
    生しない。
    • など
    • たとえばMark&SweepならSweep
    されるまでオブジェクトを解放で
    きない。
    • ときどき一気にメモリが解放され
    る時間帯が発生し、その間はアプ
    リケーションが止まる。
    • ランタイムを肥大化させやすい。
    • など

    View Slide

  30. Rust の領域と GC
    • Rust が担当する領域は、組み込みのファームウェアや OS になる。
    • 計算資源が限られた環境で動くという前提がある。
    • この制約下では、下記は困る。
    • 言語自体がメモリを多く消費する設計になっている。
    • ランタイムが大きい。
    • フル GC などでアプリケーションを止められる。

    View Slide

  31. メモリの手動管理は…
    • GC は選択肢にのぼらなくなるが、メモリの手動管理をする必要がある。
    • 速度は段違いになる。
    • メモリの手動管理はUB (Undefined Behaviour) を生みやすくなる。
    • C/C++ 製のアプリケーションではよく UB 起因の脆弱性が報告される。
    ※ サニタイザなどのツールの力を借りることはもちろんできる。
    ※ C++11からはムーブセマンティクスが導入されたが、あれはあれでいくつか課題があった。

    View Slide

  32. 事例: Chromium Project
    • Chromium は C++ 製。
    • メモリ関係の脆弱性が70%近くを
    占める。
    • ↓によるとコストは高い評価だが
    Rust も検討のテーブルに入ってい
    る。
    どちらの画像も
    https://www.chromium.org/Home/chromium-security/memory-safety
    より引用

    View Slide

  33. Rustの場合はどうしたか
    • Rust は GC を採用していない。
    • Rust は「メモリ安全はコンパイラが検査する」で解決した。
    • 「所有権」「ライフタイム」の仕組みで、メモリ安全でないコードはコンパイル時に弾く。
    • 「コンパイラが厳しい」理由はここにある。
    • この仕組みの裏側には型理論の研究成果が含まれている。
    • こうしたメモリ安全・並行処理安全の仕組みは、第2回で詳しく説明する予定。
    • 速度面と安全性のトレードオフを打破した。

    View Slide

  34. この節のまとめ
    • 従来の言語では、メモリ安全のために GC を導入した。
    • GC の導入は速度を犠牲にした。
    • 従来の言語でのメモリの手動管理は、速度は追求できた。
    • メモリの手動管理は安全性を犠牲にした。
    • Rust はメモリ安全と速度の両立を実現した。

    View Slide

  35. この節のまとめ
    • Rust はメモリ管理をコンパイラが自動で行う。
    • メモリ安全でないコードはコンパイルが通らない。
    • その分、余計な手間は増えている。
    • コンパイルを通すのが難しくなる理由もここにある。
    • というか、ソフトウェアを作るってそもそも難しい行為。
    • 難しいが、すべてのプログラマが知っておくべき知識が可視化されている。

    View Slide

  36. 言語の特長
    • 非常に実行速度が速く、パフォーマンスが安定的である。
    • GC はないが、メモリ安全・並行処理安全である。
    • メモリ安全: ダングリングポインタ、ヌルポインタなどが発生しない。
    • 並行処理安全: データ競合が発生しない。
    • 速度確保のために実装を歪める必要がない。

    View Slide

  37. ゼロコスト抽象化

    View Slide

  38. ゼロコスト抽象化とは
    • コードの抽象化を行ったとしても、追加のオーバーヘッドが発生しないこと。
    • メモリ使用量が増加しない。
    • 実行速度が低下しない。
    • Rust における「抽象化」
    • 多相性: ジェネリクス(パラメトリック多相)やトレイト(アドホック多相)。
    • 高階関数: filter や map、あるいはクロージャを引数にとる関数。
    • Future: 並行処理の抽象機構。

    View Slide

  39. 他のプログラミング言語では
    • 例: ジェネリクスを使用すると、動的ディスパッチによるオーバーヘッドが発生する。
    • 実行時に関数の抽象と実装の紐付けを行う言語がほとんど。
    • この方式を採用すると、紐付けを定義するテーブルの分のメモリ使用量が増える。
    • 関数を呼び出す度にテーブルから探すので、その分のオーバーヘッドも増える。
    • 例: for ループと for 内包表記とラムダは、全部実行速度が違う。
    • 同じことを実現したいのに、採る手法によって実行速度が変わること全般を指す。
    • いい例は Py …(おっと誰かが来たようだ。
    • 全部実行速度が違うので、プログラマは適切な手法を知っていないとすぐオーバーヘッドが発生。

    View Slide

  40. ゼロコスト抽象化のよさ
    • ゼロコスト抽象化のおかげで、下記のことは考慮しなくて良くなる。
    • 抽象化すべき箇所で、実行速度を気にしてやめる。
    • XXX という手法は速度が落ちる。YYY という手法を使うべき。
    • ZZZ を採用すると、メモリ使用量が上がるから、AAA というハックをすべき。
    • こういったワークアラウンドこそ、本当の意味での学習コストではないか?
    • 正直本質的ではない。
    • 我々はコンピュータや実装と真正面から向き合いたい。
    • ゼロコスト抽象化がないと C++ の代替は目指せないので、とても重要。

    View Slide

  41. 動的/静的ディスパッチ
    • 関数等の紐付けが実行時に解決されること。
    • 動的型付き言語の大半。ダックタイピングみたいな。
    • Java の implements X をしたとき、など。
    • 都度解決する&参照のためにテーブルを探すので、遅い。
    • ⇔静的ディスパッチ
    • 静的ディスパッチはコンパイル時に関数等の紐付けを解決すること。

    View Slide

  42. Rust では
    • 基本的に静的ディスパッチが行われる。
    • コンパイル時にジェネリクスの紐付けなどの型解決が行われる。
    • 実行時には紐付け完了後のコードが走り、実行中に紐付けは行わない。
    • あるキーワードを用いれば、動的ディスパッチもできる。

    View Slide

  43. この節のまとめ
    • 従来の言語では、抽象化によるオーバーヘッドの発生が起きることがある。
    • Rust では、ゼロコスト抽象化のおかげで、抽象化を妥協しなくてよい。
    • 安心してメンテナンス性の高いコードを、速度面で妥協せず書くことができる。

    View Slide

  44. 言語の特長のまとめ
    • 非常に実行速度が速く、パフォーマンスが安定的である。
    • GC はないが、メモリ安全・並行処理安全である。
    • メモリ安全: ダングリングポインタ、ヌルポインタなどが発生しない。
    • 並行処理安全: データ競合が発生しない。
    • 速度確保のために実装を歪める必要がない。

    View Slide

  45. Rust の言語機能
    ササッと学ぶ!

    View Slide

  46. みなさんの経験したプログラミング言語を教え
    て下さい
    アンケート

    View Slide

  47. Hello, World

    View Slide

  48. Hello, World
    • fn = 関数定義
    • println! = マクロ

    View Slide

  49. 変数

    View Slide

  50. 制御構文
    • if, for あたりは他の言語と同じように使える。
    • Pattern Matching と呼ばれる switch 文の強力版が使える。
    • 制御構文はすべて式(expression)な点に注意する。

    View Slide

  51. 制御構文

    View Slide

  52. 制御構文

    View Slide

  53. 制御構文

    View Slide

  54. データ型の作り方
    • 構造体を用いて新しいデータ型を定義する。
    • enum を用いてデータを定義する。

    View Slide

  55. データ型の作り方

    View Slide

  56. データ型の作り方

    View Slide

  57. エラーハンドリング
    • Result 型を用いた復帰可能なエラーハンドリングを行う。
    • panic を用いて修復不能なエラーハンドリングを行う。
    • 使い分けがよく議論の的になっている。

    View Slide

  58. エラーハンドリング
    • 実用上は
    • プログラム自体の想定しないバグであれば panic しておく。
    • 想定内のエラーであれば Result でハンドリングする。
    • Java とのアナロジーで考えるなら(Rust には例外機構はないことに注意)、
    • panic は非検査例外(RuntimeException)
    • Result は検査例外(Exception)

    View Slide

  59. エラーハンドリング

    View Slide

  60. エラーハンドリング

    View Slide

  61. エラーハンドリング

    View Slide

  62. 抽象化の仕方
    • 「トレイト」がキーワード。
    • パラメトリック多相(ジェネリクス)
    • アドホック多相(型クラス)
    • 今回は説明しないが、dyn Trait や impl Trait というものもある。

    View Slide

  63. パラメトリック多相

    View Slide

  64. アドホック多相

    View Slide

  65. メモリ管理の仕方
    • 所有権、ライフタイム。
    • ダングリングポインタを防止できる→安全性の源
    • 今回は説明しないがスマートポインタ。

    View Slide

  66. 所有権

    View Slide

  67. 所有権

    View Slide

  68. ライフタイム

    View Slide

  69. ライフタイム

    View Slide

  70. Rust のコンパイルエラー
    • わかりやすくない?
    • コンパイラの指示通りに直すと、安全で高速なコードが動く!
    • コンパイラは心強いもうひとりの同僚。

    View Slide

  71. マクロ
    • 基本的には関数みたいなもの。
    • メタプログラミングを可能にする。

    View Slide

  72. マクロ

    View Slide

  73. マクロ

    View Slide

  74. マクロ

    View Slide

  75. ユニットテスト
    • ファイル内に書ける。
    • `cargo test` で標準で入っていて、それを叩くだけでよい。テストランタイムが不要。

    View Slide

  76. ユニットテスト

    View Slide

  77. unsafe
    • 生ポインタを参照できるようになる。
    • 標準ライブラリの unsafe 関数を使用できる。
    • unsafe キーワード
    • unsafe fn
    • unsafe trait
    • unsafe ブロック
    • unsafe ブロック内はコンパイラが安全性保証をしない。
    • Rust は C/C++ の外部関数を呼び出す機能も持つ。

    View Slide

  78. unsafe

    View Slide

  79. Rust を実際に動かしてみよう!
    今日一番大事!

    View Slide

  80. Rust のインストール
    • https://www.rust-lang.org/ja/tools/install

    View Slide

  81. プロジェクトを作る
    • cargo new hello-rust

    View Slide

  82. Hello, World!
    • cd hello-rust
    • cargo run

    View Slide

  83. エディタどうする?
    • ご自由にどうぞ。
    • 黄金の組み合わせは VSCode に rust-analyzer をインストールすること。
    • 今後のハンズオンもそれで行うので、使ってもらえるとトラブルシュートが早くなります。
    • rust-analyzer 自体は Vim や Emacs でも使える。
    • また、IntelliJ に Rust プラグインがあります。

    View Slide