web-dev-qa-db-ja.com

Node.jsに対するHaskellの応答は何ですか?

ErlangコミュニティはNode.jsをうらやましくないのは、非ブロッキングI/Oをネイティブに行い、複数のプロセッサ(Node.jsには組み込まれていないもの)にデプロイを簡単に拡張する方法があるからです。詳細については http://journal.dedasys.com/2010/04/29/erlang-vs-node-js および Node.jsまたはErlang

Haskellはどうですか? HaskellはNode.jsの利点のいくつか、つまりマルチスレッドプログラミングに頼ることなくI/Oのブロックを回避するクリーンなソリューションを提供できますか?


Node.jsには魅力的なことがたくさんあります

  1. イベント:スレッド操作はありません。プログラマはコールバックのみを提供します(Snapフレームワークのように)
  2. コールバックは単一スレッドで実行されることが保証されています。競合状態は発生しません。
  3. 素敵でシンプルなUNIXフレンドリーAPI。ボーナス:優れたHTTPサポート。 DNSも利用できます。
  4. すべてのI/Oはデフォルトで非同期です。これにより、ロックを回避しやすくなります。ただし、コールバックでのCPU処理が多すぎると、他の接続に影響します(この場合、タスクはより小さなサブタスクに分割され、再スケジュールされる必要があります)。
  5. クライアント側とサーバー側で同じ言語。 (ただし、これにはあまり価値はありません。jQueryとNode.jsはイベントプログラミングモデルを共有しますが、残りは非常に異なります。サーバー側とクライアント側の間でコードを共有する方法がわかりません。実際に役立ちます。)
  6. これらはすべて単一の製品にパッケージ化されています。
214
gawi

さて、@-gawiが私に指摘した node.jsプレゼンテーション を少し見て、Haskellがnode.jsと比較する方法についてもう少し言えます。プレゼンテーションで、RyanはGreen Threadsの利点のいくつかを説明しますが、スレッド抽象化の欠如が不利な点であるとは思わないと言い続けています。特にHaskellのコンテキストでは、彼の立場に反対します。サーバーコードをより簡単に、より堅牢にするには、スレッドが提供する抽象化が不可欠だと思います。特に:

  • 接続ごとに1つのスレッドを使用すると、allを同時に処理するコードを作成するのではなく、単一のクライアントとの通信を表すコードを作成できます。次のように考えてください。スレッドで複数のクライアントを処理するサーバーは、単一のクライアントを処理するサーバーとほとんど同じに見えます。主な違いは、前者のどこかにforkがあることです。実装するプロトコルがまったく複雑な場合、複数のクライアントのステートマシンを同時に管理するのは非常に難しくなりますが、スレッドを使用すると、単一のクライアントとの通信をスクリプト化するだけで済みます。コードは簡単に正しくなり、理解と保守が容易になります。

  • 単一のOSスレッドでのコールバックは、スレッドで得られるプリエンプティブマルチタスクとは対照的に、協調マルチタスクです。協調マルチタスクの主な欠点は、プログラマーが飢starがないことを確認する責任があることです。モジュール性が失われます。1つの場所でミスをすると、システム全体が台無しになります。これは本当に心配する必要はありません。プリエンプションは簡単な解決策です。さらに、コールバック間の通信は不可能です(デッドロックします)。

  • haskellでは並行性は難しくありません。ほとんどのコードは純粋であり、構築によってスレッドセーフであるためです。単純な通信プリミティブがあります。 Haskellで並行性を備えた足で自分自身を撃つことは、制限のない副作用のある言語よりもはるかに困難です。

218
Simon Marlow

HaskellはNode.jsの利点のいくつか、つまりマルチスレッドプログラミングに頼ることなくI/Oのブロックを回避するクリーンなソリューションを提供できますか?

はい、実際、イベントとスレッドはHaskellで統合されています。

  • 明示的な軽量スレッド(たとえば、1台のラップトップで数百万のスレッド)でプログラミングできます。
  • または;スケーラブルなイベント通知に基づいて、非同期イベント駆動型のスタイルでプログラミングできます。

スレッドは実際には イベントの観点から実装 であり、シームレスなスレッド移行、文書化されたパフォーマンス、およびアプリケーションを使用して、複数のコア間で実行されます。

例えば。ために

32コアでの同時コレクションnbody

alt text

Haskellでは、イベントとスレッドの両方があり、すべてのイベントが内部にあるためです。

論文を読む 実装の説明。

154
Don Stewart

まず、node.jsがこれらすべてのコールバックを公開する正しいことをしているというあなたの見解を保持していません。最終的にCPS(継続渡しスタイル)でプログラムを作成することになりますが、その変換を行うのはコンパイラーの仕事だと思います。

イベント:スレッド操作はありません。プログラマはコールバックのみを提供します(Snapフレームワークのように)

したがって、これを念頭に置いて、必要に応じて非同期スタイルを使用して作成できますが、そうすることで、要求ごとに1つのスレッドで効率的な同期スタイルで作成することができなくなります。 Haskellは、特に他の言語と比較した場合、同期コードで滑luに効率的です。下にあるすべてのイベントです。

コールバックは単一スレッドで実行されることが保証されています。競合状態は発生しません。

Node.jsで競合状態が発生する可能性はありますが、より困難です。

すべての要求は、独自のスレッドにあります。他のスレッドと通信する必要があるコードを記述する場合、haskellの並行処理プリミティブのおかげでスレッドセーフにするのは非常に簡単です。

素敵でシンプルなUNIXフレンドリーAPI。ボーナス:優れたHTTPサポート。 DNSも利用できます。

ハッキングを見て、自分の目で確かめてください。

すべてのI/Oは、デフォルトでは非同期です(ただし、これは面倒な場合があります)。これにより、ロックを回避しやすくなります。ただし、コールバックでのCPU処理が多すぎると、他の接続に影響します(この場合、タスクはより小さなサブタスクに分割され、再スケジュールされる必要があります)。

そのような問題はありません。ghcは実際のOSスレッドに作業を分散します。

クライアント側とサーバー側で同じ言語。 (ただし、これにはあまり価値はありません。JQueryとNode.jsはイベントプログラミングモデルを共有していますが、残りは非常に異なっています。サーバー側とクライアント側の間でコードを共有する方法がわかりません。実際に役立ちます。)

Haskellはおそらくここで勝てないでしょう...もう一度考えてください http://www.haskell.org/haskellwiki/Haskell_in_web_browser .

これらはすべて単一の製品にパッケージ化されています。

Ghcをダウンロードし、cabalを起動します。あらゆるニーズに対応するパッケージがあります。

18
dan_waterworth

個人的には、Node.jsとコールバックを使用したプログラミングは、不必要に低レベルで少し不自然なものだと考えています。 GHCに見られるような優れたランタイムがコールバックを処理し、非常に効率的に実行できるのに、なぜコールバックを使用してプログラムするのですか?

それまでの間、GHCランタイムは大幅に改善されました。今では MIO と呼ばれる「新しいIOマネージャー」を備えています。ここで、「M」はマルチコアを表します。既存のIOマネージャーの基盤の上に構築され、その主な目標は4+コアのパフォーマンス低下の原因を克服することです。このペーパーで提供されるパフォーマンスの数値は非常に印象的です。自分を見てください:

Mioを使用すると、Haskellの現実的なHTTPサーバーは20 CPUコアに拡張され、GHCの以前のバージョンを使用した同じサーバーと比較して最大6.5倍のピークパフォーマンスを達成します。 Haskellサーバーのレイテンシも改善されています:[...]中程度の負荷の下で、GHCの以前のバージョンと比較して、予想される応答時間を5.7倍短縮します

そして:

また、Mioを使用すると、McNettle(Haskellで記述されたSDNコントローラー)が40以上のコアに効果的に拡張でき、1台のマシンで毎秒2,000万を超える新しいリクエストのスループットに達し、したがって既存のすべてのSDNコントローラーの中で最速になることを示しています。

MioはGHC 7.8.1リリースに含まれています。個人的には、これがHaskellのパフォーマンスにおける大きな前進だと考えています。以前のGHCバージョンと7.8.1でコンパイルされた既存のWebアプリケーションのパフォーマンスを比較することは非常に興味深いでしょう。

8
vlprans

1)Haskellはすでにこの問題をより良い方法で解決しており、2)Erlangとほぼ同じ方法で解決しているため、この質問はかなりばかげています。ノードに対するベンチマークは次のとおりです。 http://www.yesodweb.com/blog/2011/03/preliminary-warp-cross-language-benchmarks

Haskell 4コアを提供すると、1つのアプリケーションで毎秒10万(単純)のリクエストを実行できます。 Nodeは多くのことを実行できず、単一のアプリケーションをコア間でスケーリングできません。 Haskellランタイムは非ブロッキングなので、これを刈り取るために何もする必要はありません。ランタイムに非ブロッキングIOが組み込まれている他の(比較的一般的な)言語はErlangのみです。

5
Greg Weber

私見イベントは良いですが、コールバックによるプログラミングはそうではありません。

Webアプリケーションのコーディングとデバッグを特別なものにしている問題のほとんどは、スケーラブルで柔軟性のあるものに起因しています。最も重要なのは、HTTPのステートレスな性質です。これにより、操作性が向上しますが、これにより、IO要素(この場合はWebサーバー)がアプリケーションコード内の異なるハンドラーを呼び出す制御が逆になります。コールバックは変数スコープを共有せず、ナビゲーションの直感的なビューが失われるため、このイベントモデル、またはコールバックモデル、より正確に言うと、悪夢です。ユーザーが前後にナビゲートするときに、考えられるすべての状態変更を防止することは非常に困難です。

問題は、イベントモデルが正常に機能するGUIプログラミングに似ていますが、GUIにはナビゲーションも戻るボタンもありません。これにより、Webアプリケーションで可能な状態遷移が増加します。これらの問題を解決する試みの結果は、複雑な構成を備えた重いフレームワークであり、問​​題の根本を疑うことなく広範に広がるマジック識別子を備えています。コールバックモデルとその固有の変数スコープの共有の欠如、シーケンスなし識別子をリンクすることによって構築されます。

Ocsigen(ocaml)seaside(Smalltalk)WASH(廃止、Haskell)やmflow(Haskell)などのシーケンシャルベースのフレームワークがあり、ナビゲーションとRESTの完全性を維持しながら状態管理の問題を解決します。これらのフレームワーク内で、プログラマはナビゲーションを命令シーケンスとして表現でき、プログラムはページを送信し、単一のスレッドで応答を待機し、変数はスコープ内にあり、戻るボタンは自動的に機能します。これは本質的に、ナビゲーションがプログラマーにはっきりと見える、より短く、より安全で、より読みやすいコードを生成します。 (公正な警告:私はmflowの開発者です)

5
agocorona
1
Chawathe Vipul