web-dev-qa-db-ja.com

技術的には、なぜErlangのプロセスはOSスレッドよりも効率的ですか?

アーランの特徴

Erlang Programming (2009)から:

Erlangの並行性は高速でスケーラブルです。そのプロセスは軽量であり、Erlang仮想マシンは作成されたプロセスごとにOSスレッドを作成しません。それらは、基盤となるオペレーティングシステムに関係なく、VMで作成、スケジュール、および処理されます。その結果、プロセスの作成時間はマイクロ秒のオーダーであり、同時に存在するプロセスの数とは無関係です。これをJavaおよびC#と比較してください。すべてのプロセスで基盤となるOSスレッドが作成されます。非常に競争力のある比較が得られ、Erlangは両方の言語を大きく上回ります。

Erlangでの同時実行指向プログラミング(pdf)(slides) (2003):

Erlangプロセスの作成にかかる時間は1µsから2,500プロセスまで一定です。その後、最大30,000プロセスで約3µsに増加します。 JavaおよびC#のパフォーマンスは、図の上部に示されています。少数のプロセスでは、プロセスの作成に約300µsかかります。 2000以上のプロセスを作成することは不可能です。

最大30,000プロセスの場合、2つのErlangプロセス間でメッセージを送信する時間は約0.8µsです。 C#の場合、最大プロセス数(約1800プロセス)まで、メッセージごとに約50µsかかります。 Javaはさらに悪化し、最大100プロセスでメッセージごとに約50µsかかった後、約1000 Javaプロセスがあった場合、メッセージごとに10msに急速に増加しました。

私の考え

Erlangプロセスが新しいプロセスの生成において非常に効率的であり、プロセスごとのメモリフットプリントがはるかに小さい理由を技術的に完全には理解していません。 OSとErlang VMの両方が、スケジューリング、コンテキストの切り替えを行い、レジスタなどの値を追跡する必要があります...

単に、OSスレッドがErlangのプロセスと同じ方法で実装されないのはなぜですか?彼らはもっと何かをサポートする必要がありますか?そして、なぜ彼らはより大きなメモリフットプリントが必要なのですか?そして、なぜ彼らは産卵とコミュニケーションが遅いのですか?

技術的には、生成と通信に関して、ErlangのプロセスがOSスレッドよりも効率的なのはなぜですか?そして、なぜOSのスレッドを同じ効率的な方法で実装および管理できないのですか?そして、なぜOSスレッドのメモリフットプリントが大きくなり、生成と通信が遅くなるのですか?

もっと読む

164
Jonas

いくつかの要因があります。

  1. ErlangプロセスはOSプロセスではありません。これらは、Erlang VMにより、軽量の協調スレッドモデルを使用して実装されます(Erlangレベルでプリエンプティブですが、協調的にスケジュールされたランタイムの制御下にあります)。 、既知の制御されたポイントでのみ切り替えるため、CPUの状態全体を保存する必要がないためです(通常、SSEおよびFPUレジスタ、アドレス空間マッピングなど)。
  2. Erlangプロセスは、動的に割り当てられたスタックを使用します。スタックは非常に小さく、必要に応じて成長します。これにより、利用可能なRAMをすべて消費することなく、数千、さらには数百万ものErlangプロセスを生成できます。
  3. Erlangは以前はシングルスレッドであったため、プロセス間のスレッドセーフを確保する必要はありませんでした。現在はSMPをサポートしていますが、同じスケジューラ/コア上のErlangプロセス間の相互作用は依然として非常に軽量です(コアごとに個別の実行キューがあります)。
105
Marcelo Cantos

さらに調査した後、Joe Armstrongによるプレゼンテーションを見つけました。

Erlang-並行世界のソフトウェア(プレゼンテーション) (13分):

[Erlang]は並行言語です。つまり、スレッドはプログラミング言語の一部であり、オペレーティングシステムに属していません。 JavaやC++などのプログラミング言語では実際に問題があります。スレッドはプログラミング言語ではなく、スレッドはオペレーティングシステムに存在します。オペレーティングシステム問題の1つは、メモリ管理システムの粒度です。オペレーティングシステムのメモリ管理はメモリのページ全体を保護するため、スレッドの最小サイズはページの最小サイズです。それは実際には大きすぎます。

マシンにメモリを追加すると、メモリを保護するビット数が同じになるため、ページテーブルの粒度が上がります – 数百バイトで実行していることがわかっているプロセスに、たとえば64kBを使用することになります。

すべてではないにしても、少なくとも私の質問のいくつかに答えると思います

65
Jonas

アセンブラーにコルーチンを実装し、パフォーマンスを測定しました。

コルーチン(別名アーランプロセス)の切り替えには、最新のプロセッサで約16命令と20ナノ秒かかります。また、切り替え先のプロセスをよく知っています(例:キューでメッセージを受信するプロセスは、呼び出し元プロセスから受信プロセスへの直接のハンドオフとして実装できます)。 O(1)操作。

OSスレッドを切り替えるには、カーネルを呼び出しているため、約500〜1000ナノ秒かかります。 OSスレッドスケジューラは、O(log(n))またはO(log(log(n)))で実行されます。数万、または数百万のスレッドがある場合に顕著です。

したがって、Erlangプロセスは、スイッチングの基本操作が高速であり、スケジューラーの実行頻度が低いため、より高速で拡張性に優れています。

44
Surfer Jeff

Erlangプロセスは、(おおよそ)他の言語の 緑のスレッド に対応しています。 OSによって強制されるプロセス間の分離はありません。 (言語による分離が行われている可能性がありますが、Erlangがほとんどの場合よりも優れた仕事をしているにもかかわらず、それはあまり保護されていません。)非常に軽量であるため、はるかに広く使用できます.

一方、OSスレッドは、異なるCPUコアで単純にスケジュールでき、(ほとんど)独立したCPUバウンド処理をサポートできます。 OSプロセスはOSスレッドに似ていますが、OSによって強制される分離がはるかに強力です。これらの機能の代価は、OSスレッドと(さらには)プロセスがより高価になることです。


違いを理解する別の方法はこれです。 JVMの上にErlangの実装を書くと仮定すると(特にクレイジーな提案ではありません)、各Erlangプロセスを何らかの状態のオブジェクトにするでしょう。その後、Erlangプロセスを実行するスレッドインスタンスのプール(通常、ホストシステムのコアの数に応じてサイズ設定されます。これは、実際のErlangランタイムの調整可能なパラメーターです)。次に、使用可能な実際のシステムリソース全体で実行される作業を分散します。それは物事を行うのにかなりきちんとした方法ですが、完全に各Erlangプロセスがあまりしないという事実に依存しています。もちろん大丈夫です。 Erlangは、プログラムを実行するのはそれらの全体的なアンサンブルであるため、これらの個々のプロセスをヘビーウェイトにする必要がないように構成されています。

多くの点で、実際の問題は用語の1つです。 Erlangがプロセスと呼ぶもの(およびCSP、CCS、特にπ計算の同じ概念に強く対応するもの)は、Cの遺産を持つ言語(C++、Java、C#、他の多くの)プロセスまたはスレッドを呼び出します。 someの類似点があります(すべてが同時実行の概念を含む)が、等価性はまったくありません。だから誰かがあなたに「プロセス」と言うときは注意してください。彼らはそれを全く異なるものを意味すると理解するかもしれません…

32
Donal Fellows

Jonasは、OSスレッドをErlangプロセスと比較する際にいくつかの数値が必要だったと思います。 Programming Erlangの著者であるJoe Armstrongは、しばらく前に、OSスレッドへのErlangプロセスの生成のスケーラビリティをテストしました。彼はErlangで簡単なWebサーバーを作成し、マルチスレッドApacheに対してテストしました(ApacheはOSスレッドを使用しているため)。 1998年にさかのぼるデータを含む古いWebサイトがあります。そのサイトを1回だけ見つけることができました。そのため、リンクを提供できません。しかし、情報はそこにあります。調査の主なポイントは、Apacheが8Kプロセスのすぐ下で最大になり、手書きのErlangサーバーが10K +プロセスを処理することを示しました。

2
Jurnell

Erlangインタープリターはそれ自体を心配するだけなので、OSには他にも多くのことを心配する必要があります。

1
Francisco Soto

理由の1つは、erlangプロセスがOSではなくevm(erlang仮想マシン)で作成されるため、コストが小さいことです。

0
ratzily