なぜわざわざ学習コストを払ってまでRustを採用するのか? Webエンジニア目線でRustを考察WebエンジニアからみたRust(1)

Web開発者としての興味、関心に基づきRustを端的に紹介し、その強みや弱みについて理解を深める本連載。第1回では、Rustを採用するモチベーションとは何かを整理、考察します。

» 2021年09月30日 05時00分 公開
[藤田直己paiza]

この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。

Rustへの関心の高まり

 近年、プログラミング言語「Rust」に関する重要なニュースを多く見るようになりました。例えば以下のような記事です。

Androidの開発へ「Rust」を導入、なぜなのか

Microsoft、「Rust for Windows v0.9」を公開

実装言語を「Go」から「Rust」に変更、ゲーマー向けチャットアプリ「Discord」の課題とは

 これらの記事が指し示すことは、いわゆる「GAFAM」(Google、Amazon.com、Facebook、Apple、Microsoft)と呼ばれる米国主要IT企業および先進的なWebベンチャー企業がプロダクションユースとしてRustを採用し始めており、さらに継続的投資意欲があることを示していると考えられます。他にもRustの勢いを示すものとして以下のような記事があります。

「Rust」はなぜ人気があるのか、Stack Overflowがユーザーのコメントを紹介

 Stack Overflowにおける最も愛される言語の1位にRustが君臨しています。2016年から2020年まで5年連続でRustが1位をキープし続け、さらには2020年の結果では非常に勢いのある言語である2位のTypeScriptに19ポイントという大差をつけて1位を獲得しており、エンジニアコミュニティーにおいても極めて勢いがある言語であるように感じられます。

 これらは単なる一過性のブームなのでしょうか。手慣れた既存言語ではなく、新しい言語であるRustを利用、学習するのはなぜでしょうか。第1回ではRustを採用するモチベーションとは何かを整理、考察します。

RustとC/C++

 Rustはその開発のいきさつからして、C/C++からの移行が意識されています。Rustが出現するまでは、C/C++はハイパフォーマンス(最速、最高効率)なアプリケーションを開発するならば避けて通れない言語だとされてきました。一方でC/C++では、言語規格に動作の定義がない命令を記述することができてしまいます。その命令の結果生じる動作のことを、未定義動作と呼びます。未定義動作を引き起こす命令の典型例としては以下のようなものがあります。

  1. すでに解放されているメモリ領域を参照する(use after free)
  2. すでに解放されているメモリ領域をさらにメモリ解放する(double free)
  3. 無効なメモリ領域を指しているポインタ(ダングリングポインタ)を参照解決する
  4. 配列の範囲外アクセス
  5. 複数スレッドによるあるメモリの同時参照・更新(データ競合) etc.

 未定義動作の典型例は(厳密には予測不能ですが例えば)以下のようなものがあります。

  1. 本来アクセスできないデータを参照・更新できてしまう(不正アクセス)
  2. OSのメモリ保護機構によりメモリの不正アクセスを検出しプログラムが停止する(segmentation fault) etc.
// deref_null_pointer.c
#include <stddef.h>
int main(void)
{
  int *null_pointer = NULL;
  int value = *null_pointer; // 未定義動作発生
}
【未定義動作を起こす極めて単純なCのコード】このコードの問題は明白ですが、現実の問題はここまで簡単ではないはずです
【Cのコードの実行例】この実行ではOSのメモリ保護機構によりsegmentation faultとなりましたが、いつでもこの結果になるとは限りません
// deref_null_pointer.rs
fn main() {
    let p: *const i32 = std::ptr::null(); // null pointerそのものは安全である
    unsafe { // unsafeで囲まないとコンパイルエラー
        println!("{}", *p); // 未定義動作発生
    }
}
【未定義動作を起こすRustのコード】unsafeを使うとRustコンパイラの安全性保証から外れてしまう一方、C同等の自由度を獲得できます

 未定義動作を引き起こすプログラムは安全とは言えません。例えば、セキュリティ問題や障害を引き起こす可能性があります。未定義動作が生じないことをC/C++コンパイラは(警告は出せますが)保証しないので、プログラマーがコードを確認し保証する必要があります。未定義動作は、コンパイラによる最適化などにより予期せぬ振る舞いや非決定論的な振る舞いを生じることも多くデバッグも困難なものになりがちです。言語仕様に精通したプログラマーの尽力による問題解決が必要になります。

 Rustは、unsafeという言語機能を用いない限り未定義動作を引き起こし得る命令を記述しようとしてもコンパイル時または実行時エラー(パニック)になります。もしパニックとなったときでも決定論的に振る舞うのでデバッグがしやすく、なおかつC/C++に比肩するパフォーマンスを同時に有しています。

※この記事では上述の「未定義動作を引き起こす命令」のうち1、2、3、4のような命令から保護されている、あるいは適切な動作が規定されていることをメモリ安全、5のような命令から保護されていることをスレッド安全と呼ぶことにします。

Web開発者の視点から見たRust

 Rustはその開発のいきさつからC/C++との比較を通じて語られることが多いですが、Web開発においてC/C++を採用することはまれで、メリットと呼ばれていることがそんなに大したことではないように思えるかもしれません。

 実際のところ、Ruby、Python、JavaScriptといった典型的なWeb開発言語を用いる限り、メモリ管理を言語処理系に委譲できるためuse after freeを気にする機会はありません。また、配列の範囲外アクセスをすると実行時エラーにはなりますが言語に備わっている例外機構により守られます。動作は言語の定義する範囲内に収まり、決定論的な振る舞いを示すことが多いので、未定義動作を相手にするのに比べるとデバッグするのも比較的容易です。

 Rustと典型的なWeb開発言語の安全性や開発生産性に関するさらなる考察は次回以降改めて検討することにして、ここではパフォーマンスに着目することにします。

 伝統的なWebアプリケーションは計算時間よりもネットワークI/Oがボトルネックになることが多く、複雑なデータクエリ処理はデータベースに処理を委譲するよう設計することが基本とされています。そのため、Webアプリケーション自体の計算パフォーマンスはそれほど重視されない傾向にあります。そしてそれが比較的低速な言語でWeb開発してもよい理由であり、C/C++が採用されてこなかった理由だと考えられます。

 一方でWeb開発の文脈において計算パフォーマンスが改善されるとどのようなメリットがあるのかを思い付く範囲で列挙してみます。

  1. メモリ使用量の低減→アプリケーション安定性の向上
  2. バッチ計算時間の短縮→アプリケーション安定性、計算スループットの向上
  3. 必要となるクラウドリソースが少なくできる→運用コスト削減
  4. 計算時間改善→事前計算テーブルが不要に→技術的負債の削減
  5. 計算時間改善→サーバレスポンスタイム改善→ユーザーエクスペリエンスの改善

 安全性とパフォーマンスを両立させるRustを使用することによって、「サービスの提供価値」「サイトリライアビリティ」「ユーザーエクスペリエンス」「運用コスト」など、今日のサービス開発における重要なファクターを安全性を確保しながら改善していけることが期待できます。一方で開発生産性への影響などは客観的に語ることがかなり難しいですが、次回以降検討を深めます。

Rustの卓越性、あるいは特異性

 この世にはすでにたくさんのプログラミング言語があります。その中でRustの卓越性、あるいは特異性とも呼ぶべき要素について主観的な説明を交えて紹介します。

 Rust以前の代表的な言語はメモリ安全性とGC(ガベージコレクタ)が不可分なものとして扱われており、メモリ安全性を得るためにはGCを使わなければならないという関係にありました。でなければ、人間がメモリ安全であることを保証する必要があります。

 一方でRustは「所有権システム」と呼ばれるモデルを採用し、コンパイル段階でメモリ安全性を検証することで、GCがオプトアウトできることを示しました。さらにその所有権モデルはコンパイル段階でのスレッド安全性を検証することにも利用できて、データ競合も合わせて検出します(これは実に驚くべきことで、私がRustを学習し始めた重要なモチベーションの一つになります)。

 所有権システムがRustの卓越性の根幹となるものと筆者は考えていますが、同時にRustは現代的な言語であり、さまざまな点において妥協のない言語設計になっていると強く感じます。ドキュメンテーション、依存性管理、テスト、エラーハンドリング、合理的な構文――これらのトピックに関する明確な答えをRustは提示していて、それらもまたRustの卓越性を構成しています。

まとめ

 第1回では、Rustへのモチベーションと題して、Rustの魅力やWeb開発者目線でのRustのメリットについて提示しました。第2回では、PythonとRustの構文比較をしながら、パフォーマンスについて簡易なベンチマークを取ることを予定しています。そのままパフォーマンス比較をすると自明で退屈な結果になるため、Python側も少し工夫をしてもう一歩踏み込んだ比較をしていきます。

筆者紹介

藤田直己

1988年生まれ、大阪府枚方市出身

京都大学工学部電気電子工学科卒、同大学エネルギー科学研究科修了

応用情報技術者・情報処理安全確保支援士試験合格者

YKK AP株式会社にて超高層建築物の外装設計に従事し、型・モジュール設計・ウオーターフォールプロセスに精通する。その後ITエンジニアに転向。paiza株式会社にて、Ruby on RailsやVueを用いたWebサービスのスクラム開発に従事、現在に至る。

最も得意な言語はPython、最も影響を受けた言語はClojureであり、シンプルな関数型(的書き方ができる)言語を好む。関数型的記法を持ちながら、実行性能が高いRustに興味を持ち研さんを続けている。


Copyright © ITmedia, Inc. All Rights Reserved.

スポンサーからのお知らせPR

注目のテーマ

Microsoft & Windows最前線2025
AI for エンジニアリング
ローコード/ノーコード セントラル by @IT - ITエンジニアがビジネスの中心で活躍する組織へ
Cloud Native Central by @IT - スケーラブルな能力を組織に
システム開発ノウハウ 【発注ナビ】PR
あなたにおすすめの記事PR

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。