私は読んでいる 「実行中のエリクシル」サシャ・ユリッチの本、そして最初の章 それは言う:
Erlangプロセスは互いに完全に分離されています。メモリを共有せず、1つのプロセスがクラッシュしても他のプロセスがクラッシュすることはありません。
Javaスレッドにも当てはまりますか?Javaスレッドがクラッシュした場合、他のスレッドもクラッシュしません-特に探している場合は、リクエスト処理スレッド(この議論からmain
スレッドを除外します)
私の後に繰り返します:「これらは異なるパラダイムです」
それを20回ほど声に出して言ってください-それは今のところ私たちのマントラです。
本当にリンゴとオレンジを比較しなければならない場合、少なくとも「実在」の共通の側面がどこで交差するかを考えましょう。
Java「オブジェクト」は、Javaプログラマーの計算の基本単位です。つまり、object(基本的にはカプセル化された腕と脚を持つ構造体 C++よりも多少厳密に強制されます )世界をモデル化するための主要なツール。 「このオブジェクトはData {X,Y,Z}
を知っている/持っており、Functions {A(),B(),C()}
を実行し、どこにでもData
を持ち、パブリックインターフェイスの一部として定義された関数/メソッドを呼び出すことで他のオブジェクトと通信できます。それは名詞であり、その名詞は does stuff。 "です。つまり、あなたはあなたの思考プロセスをこれらの計算単位の周りに向けます。デフォルトのケースでは、オブジェクト間で発生することが順番に発生し、クラッシュがそのシーケンスを中断します。それらは「オブジェクト」と呼ばれるため、(アランケイの元の意味を無視すると)「オブジェクトの向き」を取得します。
Erlangの「プロセス」は、Erlangプログラマーの計算の基本単位です。 process(基本的に、独自の時間と空間で実行される自己完結型のシーケンシャルプログラム)は、Erlangerがworld(1)をモデリングするための主要なツールです。 。 Javaオブジェクトがカプセル化のレベルを定義する方法と同様に、Erlangプロセスはカプセル化のレベルも定義しますが、Erlangの場合、計算単位は completely cutです互いに離れています。別のプロセスでメソッドまたは関数を呼び出すことも、その中に存在するデータにアクセスすることも、1つのプロセスが他のプロセスと同じタイミングコンテキスト内で実行することもできず、メッセージ受信の相対的な順序に関する保証はありませんメッセージを送信している可能性のある他のプロセスに。彼らは完全に異なる惑星にいる可能性があります(そして、考えてみると、これは実際にもっともらしいです)。彼らは互いに独立してクラッシュする可能性があり、他のプロセスは、影響を受けることを意図的に選択した場合にのみ影響を受けます(さらに、これにはメッセージングが含まれます:本質的に、それ自体が何らかの種類で到着することが保証されていないデッドプロセスから自殺ノートを受信するように登録するシステム全体に相対的な順序で、あなたが反応することを選択する場合もしない場合もあります)。
Javaは、複合アルゴリズムで複雑さを直接処理します。つまり、問題を解決するためにオブジェクトがどのように連携するかです。単一の実行コンテキスト内でこれを行うように設計されており、Javaのデフォルトのケースは順次実行です。 Javaの複数のスレッドは、複数の実行中のコンテキストを示し、異なるタイミングコンテキストのアクティビティが互いに影響するため(およびシステム全体:防御的プログラミング、例外スキームなど)、非常に複雑なトピックです。 )。 Java means で「マルチスレッド」と言うことは、Erlangの場合とは異なります。実際、これは常にベースケースであるため、Erlangでは言われません。 。ここで、Javaスレッドは、メモリまたは可視参照ではなく、時間に関連する分離を意味することに注意してください。Javaの可視性は、プライベートとパブリックを選択して手動で制御されます。システムの普遍的にアクセス可能な要素は、「スレッドセーフ」かつリエントラントになるように設計され、キューイングメカニズムを介してシーケンシャル化されるか、ロックメカニズムを採用する必要があります。要するに、スケジューリングは、スレッド化された/並行のJavaプログラムで手動で管理される問題です。
Erlangは、実行タイミング(スケジューリング)、メモリアクセス、参照の可視性の観点から各プロセスの実行コンテキストを分離し、そうすることで、アルゴリズムの各コンポーネントを complete /に分離することで単純化します。これは単なるデフォルトのケースではなく、この計算モデルで利用可能な唯一のケースです。これは、処理シーケンスの一部がメッセージバリアを超えると、特定の操作のシーケンスを正確に知ることができなくなるという犠牲を伴います-メッセージはすべて本質的にネットワークプロトコルであり、特定の範囲内での実行を保証できるメソッド呼び出しがないためです環境。これは、オブジェクトごとにJVMインスタンスを作成し、ソケット間でのみ通信できるようにすることに似ています-これはJavaではとてつもなく面倒ですが、Erlangが動作するように設計されている方法です(偶然、これも概念の基礎です)流行語が伴う傾向のあるWeb指向の荷物を捨てた場合に「Javaマイクロサービス」を書くこと-Erlangプログラムは、デフォルトではマイクロサービスの群れです)。そのトレードオフについてのすべて。
これらは異なるパラダイムです。最も近い共通点は、プログラマーの観点から、ErlangプロセスはJavaオブジェクトに類似していると言うことです。 Javaスレッドと比較する何かを見つけなければならない場合、Erlangにはそのような比較可能な概念がないため、Erlangでそのようなものを見つけることはできません。死んだ馬を倒すには:これらは異なるパラダイムです。 Erlangで自明ではないプログラムをいくつか書くと、これはすぐに明らかになります。
「これらは異なるパラダイムです」と言っているが、OOP vs FPのトピックには触れていないことに注意してください。 「Javaで考える」と「Erlangで考える」の違いは、OOP対FPよりも根本的です。
Erlangの「同時実行指向」または「プロセス指向」の基盤は、アランケイが「オブジェクト指向」(2)という用語を生み出したときに念頭に置いていたものに近いことは事実ですが、それはここでのポイントではありません。ケイが得たのは、コンピューターを個別のチャンクに分割することでシステムの認知の複雑さを軽減できることであり、そのためには分離が必要です。 Javaは、本質的に基本的な手続きを残す方法でこれを実現しますが、「クラス定義」と呼ばれる高次のディスパッチクロージャー上の特別な構文の周りのコードを構築します。 Erlangは、実行中のコンテキストをオブジェクトごとに分割することでこれを行います。これは、Erlangのものは互いにメソッドを呼び出せないが、Javaものは呼び出すことができることを意味します。つまり、Erlangのものは単独でクラッシュできますが、Javaものはできません。この基本的な違いから膨大な数の含意が流れます。したがって、「異なるパラダイム」です。トレードオフ。
脚注:
ほとんど間違いない。 Javaのすべてのスレッドは同じアドレス空間を共有するため、あるスレッドが別のスレッドが所有するものを破壊する可能性があります。ErlangVM this justn '各プロセスは他のすべてのプロセスから分離されているので、それが可能です。それがすべてのポイントです。あるプロセスに別のプロセスのデータを処理させたい場合は、コードが他のプロセスにメッセージを送信する必要があります。は大きなバイナリオブジェクトであり、これらは不変です。
実際、Javaプロセスはメモリを共有できます。たとえば、同じインスタンスを2つの別個のスレッドに渡すことができ、両方がその状態を操作できるため、 deadlocks などの潜在的な問題が発生します。
一方、Elixir/Erlangは不変性の概念によってこれに対処するため、プロセスに何かを渡すとき、それは元の値のコピーになります。
Javaスレッドが死ぬと、他のスレッドにも影響しません
反対質問をさせてください:なぜThread.stop()
は10年以上廃止されていると思いますか?その理由は、正確に上記の文の否定です。
2つの特定の例を挙げます:stop()
またはSystem.out.println()
のように無害に聞こえる何かを実行している間、あなたはMath.random()
スレッドです。結果:これらの2つの機能は、JVM全体で壊れています。同じことは、アプリケーションが実行する他の同期コードにも関係します。
リクエスト処理スレッドを見ている場合
アプリケーションは、ロックによって保護された共有リソースが絶対に使用されないように理論的にコーディングできます。ただし、これはJavaスレッドが相互依存している正確な範囲を指摘するのに役立ちます。達成される「独立性」は、allそのようなアプリケーションのスレッド。
以前の回答を補完するために、Javaスレッドにはデーモンと非デーモンの2つのタイプがあります。
スレッドのタイプを変更するには、 .setDaemon(boolean on)
を呼び出します。違いは、デーモンスレッドがJVMの終了を妨げないことです。スレッドのJavadocが言うように:
Java仮想マシンは、実行中のスレッドがすべてデーモンスレッドのみである場合に終了します。
つまり、ユーザースレッド(特にデーモンに設定されていないスレッド)は、JVMの終了を防ぎます。一方、デーモン以外のスレッドがすべて終了すると、デーモンスレッドが実行される場合があり、その場合、JVMは終了します。それで、あなたの質問に答えるために:終了時にJVMを終了しないスレッドを開始できます。
Erlang/Elixirとの比較については、忘れないでください:これらは、すでに述べたように、異なるパラダイムです
JVMがErlangの動作を模倣することは不可能ではありませんが、意図したものではないため、多くのトレードオフが伴います。以下のプロジェクトはそれを達成しようとします:
Javaスレッドにも当てはまりますか?Javaスレッドがクラッシュした場合、他のスレッドもクラッシュしません
はい、いいえ。説明します。
共有メモリの参照:Javaプロセスの異なるスレッドはヒープ全体を共有するため、スレッドは膨大な数の計画的および計画外の方法で対話できます。ただしスタック(たとえば、呼び出されたメソッドに渡すコンテキスト)またはThreadLocal
は、独自のスレッドです(参照の共有を開始しない限り)。
クラッシュ:スレッドがJava(Throwable
がThread.run()
に伝播されるか、何かがループまたはブロックされる)でクラッシュした場合、その事故は他に影響しない可能性がありますスレッド(たとえば、サーバー内の接続のプールは動作し続けます)ただし異なるスレッドが相互作用します。他のスレッドは、それらの1つが異常終了すると簡単に取り残されます(たとえば、1つのスレッドが終わりを閉じなかった別のスレッドからの空のパイプ)。 妄想 慎重に、副作用が発生する可能性が非常に高いです。
他のパラダイムは、スレッドが完全に独立した島として動作することを意図しているのではないかと思います。情報を共有し、何らかの形で調整する必要があります。そして、物事を台無しにする機会があります。彼らが「あなた自身を掛けるロープを少なくする」(ポインタと同じイディオム)のは、より防御的なアプローチを取るだけです。