この投稿では、GoLang、Zig、Rust を比較してみます。そして、なぜこの比較では Rust が (私にとって) 勝っているのか。
私は GoLang、Zig、Rust で 3 つのプロジェクトを書きました。これらのプロジェクトは、言語の基礎、欠点、言語、フレームワーク、エコシステムに問題があるかどうかについてよく理解するのに十分な規模です。
ヒント: 答えだけを知りたい場合は、自由に TLDR セクションにジャンプしてください。
私は数か月前に、最初は GoLang を使って開発者ツールの構築を始めました。
最初のものは基本的なデータベース管理および移行ユーティリティ (dbdaddy) で、GoLang を使って作業するのは本当に楽しかったです。
Advent Of Code や 10 億行のチャレンジ問題よりも本格的なものを GoLang で構築するのは初めての試みでしたが、習熟するまでに 1 週間もかからなかったのには驚きました .
この間ずっと、私は横でジグをいじっていました(それほど深刻なことはありませんでした)。 Redis がライセンスを「技術的には非オープンソース」ライセンスに変更したという話を聞きました。
そして私はこう思いました: zig で新しいオープンソース Redis を構築するのはどれほど難しいでしょうか?
2 か月後早送り: くそー。
「GbCache」の背後にある基本的なアイデアは、LRU ベースのメモリ内キャッシュでしたが、実際の真実の情報源は、発生した特定のキー/値の変更に関する通知や、明らかにキーに割り当てられた TTL などの機能とともにディスクに保存されることでした。
Zig がいかに明示的であるかは印象的であり、そのおかげでさらにシンプルで扱いやすくなっています。
「明日 HyperScale™ になったら負荷に耐えられるか?」という観点から GbCache を始めました
この観点から、私は GoLang を除外することにしました。メモリ割り当てについて極めて確実に推論できなければ、速度を完全に制御できないからです。
この観点から物事を行うことは、本当に素晴らしい学習体験です。なぜなら、プログラム内の爆発、メモリ不足、またはボトルネックになる可能性のあるすべてのポイント (コード内のホット パス.
Zig の明示的なおかげで、メモリをいつどこに割り当てるのかが正確にわかりました。
しかし...Zig は結局のところメモリセーフな言語ではありませんし、私はエベレスト級のスキルの問題を抱えた人間です。
サビに入ります
過去 2 年間で、私は Rust を 3 回試してみて激怒してやめました。 MacBook m69 maxes に数十億 GB の RAM を積んでいる JavaScript のバックグラウンドを持つ私は、Rust になぜそのようなルールがあるのか本当に 理解できませんでした。誇大宣伝に乗り出すのはおそらく悪い角度から見るのではなかったでしょう。 .
私は何度も激怒して辞めましたが、Rust はまだ頭の片隅にあり、その奇妙な構文、イライラするメモリ規則、そして気が遠くなるような寿命がありました。
しかし、Zig を書いているときに何かが思い当たりました...私はすでにこれらすべての記憶規則と寿命を追跡していましたが、精神的なオーバーヘッドとして.
Rust がすでに行っていることを実行しようとしている Zig コードのパターンとボイラープレートに気づき始めました。
SFS (SFW 名 - 「Simple File Storage」) 用の CLI クライアントを構築しているときに、Rust をもう一度試してみることにしました。
今回、Rust 本を読んでいるうちに、すべての「理由」を感じ始めました。
私が Rust で気に入っている最も基本的な点は、メモリの所有権と借用に基づいたメンタル モデルです。
所有および参照されるメモリのこのモデルは想像上のものですが、これは推論するのに便利なメンタル モデルであり、オーバーヘッドが少なくなります。
C や Zig のような言語が頭の中で受ける古典的な精神記憶モデルとは対照的です。 頭の中で個々のメモリ割り当てとその有効期間を追跡する必要がありますか?いいえ、ありがとうございます!
あなたが日常のバックエンド エンジニアで、スプリント パフォーマンスの数値を計算するのが好きなら、おそらく GoLang が最良の選択です。
「でも私の会社は GoLa を使用していません—」
「会社を辞めて、会社を辞めて、ツールに適した仕事を使いましょう。会社を辞めてください。」
私にとって、GoLang はお見合い結婚のようなもので、決して心の中で焦りを感じることはありませんが、決して失望することはありません。乗るか死ぬかの相棒であり、一生を賭けることができます。それ。
しかし、もしあなたがその焦りを探しているなら、読み続けてください!
でも、私はそのラッシュが欲しいのです...彼らの ey 構文を一目見ただけで心臓が爆発するのを感じたいです...彼らと一緒にいるとき、天国にいるような気分になりたいです私がいないときは地獄です...
Rust におけるマルチスレッドの安全性の例を簡単に見てみましょう。
use std::thread; fn main() { let mut counter = Box::new(0); // 32-bit integer allocated on the heap let mut handles = vec![]; for _ in 0..10 { let handle = thread::spawn(|| { *counter += 1; // trying to edit the value }); handles.push(handle); } for handle in handles { handle.join().unwrap(); // WAITING FOR ALL THE THREADS TO COMPLETE } println!("Result: {}", *counter); }
ヒープに割り当てられた値があり、それを個別に変更しようとしている 10 個のスレッドがあります。
すべてのスレッドが同時にカウンターを変更しようとするため、このコードはカウンター変数に安全にアクセスしていません。
他の言語でも、同様のコードは問題なくコンパイルして実行できます。
以前にマルチスレッド環境で作業したことがある場合は、カウンタ変数を更新する際の競合状態を防ぐために「ミューテックス」を使用することを最初に考えるかもしれません。
しかし、大規模なコードベースでは人的ミスにより、このような小さなことを見逃しがちです。
Rust ではこのプログラムをコンパイルすることさえできません。
所有権と借用のルールにより、コンパイラは、for ループの最初の反復の最初のスレッドでカウンターを可変的に借用していることを検出します... ここまでは問題ありません... 2 番目の反復同時にカウンターを可変的に借用したいですか? 危険です! コンパイル時エラーを発生させます!!.
変更/変更を目的とした所有者からの値の参照または「借用」は、「可変借用」と呼ばれます
use std::thread; fn main() { let mut counter = Box::new(0); // 32-bit integer allocated on the heap let mut handles = vec![]; for _ in 0..10 { let handle = thread::spawn(|| { *counter += 1; // trying to edit the value }); handles.push(handle); } for handle in handles { handle.join().unwrap(); // WAITING FOR ALL THE THREADS TO COMPLETE } println!("Result: {}", *counter); }
このような状況では、他の言語ではまったくエラーが発生しません。正確さを検査するのはあなたの責任ですが、Rust はそれを防ぎます。
このような構文は言語全体に広がっており、(頻繁に)足を撃たれるのを防ぐのに役立ちます。
それは状況によります!
私は本当に、答えとなる言語があればいいのにと思っています。たとえ GoLang がそれにかなり近づいたとしても、それはあなたのユースケース、そして最も重要なことにあなたのチームによって決まります。
私にとって、Rust は楽しく作業できます (今のところは誰にもわかりません...ふふふ)
TigerBeetle の人々は Zig に挑戦し、満足しています。
Primeagen は Zig に満足しています。
ジャレッド・サムナーの場合、ジグは問題ありません。彼はブンをジグで書きました。
ミッチェル・ハシモト (HashiCorp の背後にいる人) は、超高速の端末である Zig でゴーストを書いています—
.
.
.
待って...
以上が話題のプログラミング言語をすべて試してみたの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。