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

第1回 Rust Hands-On

68dad178ea4fa6aa86862b3a66a15306?s=47 Yuki Toyoda
February 17, 2021
1.8k

第1回 Rust Hands-On

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

68dad178ea4fa6aa86862b3a66a15306?s=128

Yuki Toyoda

February 17, 2021
Tweet

Transcript

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

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

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

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

    実際に環境構築をして Hello, World! する。
  5. 本日お話し すること • Rust はどのような言語か? • Rust の言語機能 • Rust

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

    を実際に動かしてみよう!
  7. Rust はどの ような言語 か? • Rust 概要 • 言語の特長 •

    Rust の速さ • GC とメモリ安全 • ゼロコスト抽象化
  8. Rust に どんなイメージがありますか? アンケート!

  9. Rust 概要

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

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

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

  13. 2020年のRustの調 査 • Rust は毎年、言語に関するアンケー トを取っている。 • Webバックエンドの利用例が1位。 • 分散システム、組み込みデバイスな

    どが続く。 • 観測範囲では、仮想通貨やブロック チェーンでの利用例も多く感じる。 https://blog.rust-lang.org/2020/04/17/Rust-survey-2019.htmlより引用。 画像はランキングの一部を切り取り。
  14. 言語のカテゴライズ • 静的型付き言語。 • 型クラス指向あるいはムーブセマンティクス指向。 • マルチパラダイムプログラミング言語(Scala などが該当する)。 • 書き味は普通の命令型プログラミング言語(C

    や Java)。 • 関数型プログラミング言語ではない。
  15. 言語の特長 • 非常に実行速度が速く、パフォーマンスが安定的である。 • GC はないが、メモリ安全・並行処理安全である。 • メモリ安全: ダングリングポインタ、ヌルポインタなどが発生しない。 •

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

    並行処理安全: データ競合が発生しない。 • 速度確保のために実装を歪める必要がない。
  17. Rust の速さ ベンチマークゲームズを参考にして知る

  18. C, Go, Java, Node.js, PHP, Python3, Swift を 実行速度の速い順に並べ替えてみてください! クイズ

  19. Benchmark Games • 今回参考にするサイトは Benchmark Games というサイト。 • https://benchmarksgame-team.pages.debian.net/benchmarksgame/index.html •

    ここでいう速さとは、純粋にコード自体の実行時間のことを指している。
  20. Rust の速さはいかほど? • Go や Java よりもさらに速い。 • C/C++ と並ぶかさらに速い。

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

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

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

  24. その他語られる話として • Rust には GC がない。 • このおかげで、メモリ使用量などの予測が立てやすい。 • GC

    の気まぐれでパフォーマンスが変わるといった影響を受けにくい。
  25. この節のまとめ • Rust は地球上に存在する利用者の多い言語の中では最速の部類に入る。 • Rust の速さの根本要因は C/C++ と似た話になっている。 •

    GC がないこと。 • VM などを挟まず、機械語に直接コンパイルすること。
  26. 言語の特長 • 非常に実行速度が速く、パフォーマンスが安定的である。 • GC はないが、メモリ安全・並行処理安全である。 • メモリ安全: ダングリングポインタ、ヌルポインタなどが発生しない。 •

    並行処理安全: データ競合が発生しない。 • 速度確保のために実装を歪める必要がない。
  27. GC とメモリ安全

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

  29. GC のメリデメ メリット デメリット • メモリ管理を手動でしなくていい 。 • コード上にメモリ管理に関する追 加のノイズがなくなる。

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

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

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

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

    「所有権」「ライフタイム」の仕組みで、メモリ安全でないコードはコンパイル時に弾く。 • 「コンパイラが厳しい」理由はここにある。 • この仕組みの裏側には型理論の研究成果が含まれている。 • こうしたメモリ安全・並行処理安全の仕組みは、第2回で詳しく説明する予定。 • 速度面と安全性のトレードオフを打破した。
  34. この節のまとめ • 従来の言語では、メモリ安全のために GC を導入した。 • GC の導入は速度を犠牲にした。 • 従来の言語でのメモリの手動管理は、速度は追求できた。

    • メモリの手動管理は安全性を犠牲にした。 • Rust はメモリ安全と速度の両立を実現した。
  35. この節のまとめ • Rust はメモリ管理をコンパイラが自動で行う。 • メモリ安全でないコードはコンパイルが通らない。 • その分、余計な手間は増えている。 • コンパイルを通すのが難しくなる理由もここにある。

    • というか、ソフトウェアを作るってそもそも難しい行為。 • 難しいが、すべてのプログラマが知っておくべき知識が可視化されている。
  36. 言語の特長 • 非常に実行速度が速く、パフォーマンスが安定的である。 • GC はないが、メモリ安全・並行処理安全である。 • メモリ安全: ダングリングポインタ、ヌルポインタなどが発生しない。 •

    並行処理安全: データ競合が発生しない。 • 速度確保のために実装を歪める必要がない。
  37. ゼロコスト抽象化

  38. ゼロコスト抽象化とは • コードの抽象化を行ったとしても、追加のオーバーヘッドが発生しないこと。 • メモリ使用量が増加しない。 • 実行速度が低下しない。 • Rust における「抽象化」

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

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

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

    をしたとき、など。 • 都度解決する&参照のためにテーブルを探すので、遅い。 • ⇔静的ディスパッチ • 静的ディスパッチはコンパイル時に関数等の紐付けを解決すること。
  42. Rust では • 基本的に静的ディスパッチが行われる。 • コンパイル時にジェネリクスの紐付けなどの型解決が行われる。 • 実行時には紐付け完了後のコードが走り、実行中に紐付けは行わない。 • あるキーワードを用いれば、動的ディスパッチもできる。

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

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

    並行処理安全: データ競合が発生しない。 • 速度確保のために実装を歪める必要がない。
  45. Rust の言語機能 ササッと学ぶ!

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

  47. Hello, World

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

  49. 変数

  50. 制御構文 • if, for あたりは他の言語と同じように使える。 • Pattern Matching と呼ばれる switch

    文の強力版が使える。 • 制御構文はすべて式(expression)な点に注意する。
  51. 制御構文

  52. 制御構文

  53. 制御構文

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

  55. データ型の作り方

  56. データ型の作り方

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

  58. エラーハンドリング • 実用上は • プログラム自体の想定しないバグであれば panic しておく。 • 想定内のエラーであれば Result

    でハンドリングする。 • Java とのアナロジーで考えるなら(Rust には例外機構はないことに注意)、 • panic は非検査例外(RuntimeException) • Result は検査例外(Exception)
  59. エラーハンドリング

  60. エラーハンドリング

  61. エラーハンドリング

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

    や impl Trait というものもある。
  63. パラメトリック多相

  64. アドホック多相

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

  66. 所有権

  67. 所有権

  68. ライフタイム

  69. ライフタイム

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

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

  72. マクロ

  73. マクロ

  74. マクロ

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

  76. ユニットテスト

  77. unsafe • 生ポインタを参照できるようになる。 • 標準ライブラリの unsafe 関数を使用できる。 • unsafe キーワード

    • unsafe fn • unsafe trait • unsafe ブロック • unsafe ブロック内はコンパイラが安全性保証をしない。 • Rust は C/C++ の外部関数を呼び出す機能も持つ。
  78. unsafe

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

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

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

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

  83. エディタどうする? • ご自由にどうぞ。 • 黄金の組み合わせは VSCode に rust-analyzer をインストールすること。 •

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