web-dev-qa-db-ja.com

scala vs Java、パフォーマンス、メモリ?

私はScalaを詳しく調べたいと思いますが、答えが見つからないような基本的な質問が1つあります。一般的に、ScalaとJavaのパフォーマンスとメモリ使用量に違いはありますか?

155
JohnSmith

私は新しいユーザーなので、上記のRex Kerrの回答にコメントを追加することはできません(新しいユーザーに「コメント」ではなく「回答」を許可するのは非常に奇妙なルールです)。

上記のRexの一般的な答えを暗示する「うわー、Javaは非常に冗長で大変な仕事です」に単に答えるためにサインアップしました。もちろん、より簡潔なScalaコードを記述できますが、Javaの例は明らかに肥大化しています。ほとんどのJava開発者は、次のようなコードを作成します。

List<String> bigEnough = new ArrayList<String>();
for(String s : array) {
  if(s.length() > 2 && mapping.get(s) != null) {
    bigEnough.add(mapping.get(s));
  }
}

もちろん、Eclipseが実際のタイピングのほとんどを行わず、保存されたすべての文字が本当に優れたプログラマーになるというふりをするなら、これをコーディングできます。

List b=new ArrayList();
for(String s:array)
  if(s.length()>2 && mapping.get(s) != null) b.add(mapping.get(s));

今では、完全な変数名と中括弧を入力するのにかかった時間を節約しただけでなく(アルゴリズムの深い考えを考えるのにさらに5秒を費やすことができます)、難読化コンテストにコードを入力して、休日。

100
Not Sleeping

ScalaをJavaのように書くと、ほぼ同一のバイトコードがほぼ同一のメトリックで出力されることが期待できます。

不変オブジェクトと高階関数を使用して、より「イディオマティック」に記述してください。少し遅くなり、少し大きくなります。この経験則の1つの例外は、型パラメーターが@specialised注釈を使用するジェネリックオブジェクトを使用する場合です。これにより、ボクシング/アンボクシングを回避することでJavaのパフォーマンスを上回ることができるさらに大きなバイトコードが作成されます。

また、言及する価値があるのは、並行して実行できるコードを作成する場合、メモリの増加/速度の低下が避けられないトレードオフであるという事実です。慣用的なScalaコードは、典型的なJavaコードよりも本質的にはるかに宣言的であり、多くの場合、完全に並列であることからわずか4文字(.par)離れています。

だから

  • Scalaコードは、単一スレッドでJavaコードよりも1.25倍長くかかります
  • 簡単に 4つのコアに分割できます(ラップトップでも一般的です)
  • (1.24/4 =)0.3125xの元のJavaの並列実行時間

Scalaコードは現在25%遅い、または3倍速いと言うでしょうか?

正しい答えは、「パフォーマンス」の定義方法によって異なります。

64
Kevin Wright

コンピュータ言語のベンチマークゲーム:

速度テスト Java/scala 1.71/2.25

メモリテスト Java/scala 66.55/80.81

したがって、このベンチマークでは、Javaは24%高速であり、scalaは21%多いメモリを使用します。

全体としては大したことではなく、ほとんどの時間がデータベースとネットワークによって消費される現実のアプリでは重要ではありません。

一番下の行:Scalaがあなたとあなたのチーム(そしてあなたが去るときにプロジェクトを引き継ぐ人)の生産性を高めるなら、あなたは頑張れ。

31
Peter Knego

タイトループに関してこの質問に答えた人もいますが、私がコメントしたRex Kerrの例には明らかなパフォーマンスの違いがあるようです。

この答えは、設計上の欠陥としてタイトループ最適化の必要性を調査する可能性のある人々を本当に対象としています。

私はScala(約1年程度)に比較的新しいですが、これまでの感触は、の多くの側面を延期できることです設計、実装、実行は比較的簡単です(十分なバックグラウンドの読み取りと実験が必要です)。

遅延設計機能:

遅延実装機能:

遅延実行機能:(申し訳ありませんが、リンクはありません)

  • スレッドセーフな遅延値
  • 名前で渡す
  • モナド的なもの

私にとって、これらの機能は、高速でタイトなアプリケーションへの道を踏み出すのに役立つものです。


Rex Kerrの例は、実行のどの側面が延期されるかが異なります。 Javaの例では、Scalaの例がマッピングルックアップを遅らせるサイズが計算されるまで、メモリの割り当てが延期されます。私には、それらは完全に異なるアルゴリズムのように見えます。

私が考えるのは、彼のJavaの例に相当するものです。

val bigEnough = array.collect({
    case k: String if k.length > 2 && mapping.contains(k) => mapping(k)
})

中間コレクションやOptionインスタンスなどはありません。これにより、コレクションタイプも保持されるため、bigEnoughのタイプはArray[File]-Arraycollect実装はおそらく何かを実行します。カー氏のJavaコードの行。

上記の遅延設計機能により、ScalaのコレクションAPI開発者は、APIを壊すことなく、将来のリリースでその高速な配列固有のコレクション実装を実装できます。これは私が速度への道を踏み出すことで言及していることです。

また:

val bigEnough = array.withFilter(_.length > 2).flatMap(mapping.get)

ここでwithFilterの代わりに使用したfilterメソッドは、中間コレクションの問題を修正しますが、Optionインスタンスの問題はまだあります。


Scalaの単純な実行速度の1つの例は、ロギングです。

Javaには次のように記述できます。

if (logger.isDebugEnabled())
    logger.debug("trace");

Scalaでは、これは次のとおりです。

logger.debug("trace")

Scalaでデバッグするメッセージパラメーターの型は "=> String"であるため、評価時に実行されるパラメーターなしの関数と考えられますが、ドキュメントではpass-by-名前。

EDIT {Scalaの関数はオブジェクトであるため、ここに余分なオブジェクトがあります。私の仕事にとって、些細なオブジェクトの重みは、ログメッセージが不必要に評価される可能性を取り除く価値があります。 }

これによりコードは高速になりませんが、高速になる可能性が高くなり、他の人のコードをまとめてクリーンアップする経験が少なくなります。

私にとって、これはScala内で一貫したテーマです。


ハードコードは、Scalaが高速である理由をキャプチャできませんが、少しヒントがあります。

これは、Scalaでのコードの再利用とコード品質の上限の組み合わせだと思います。

Javaでは、素晴らしいコードはしばしば理解できない混乱に追い込まれます。そのため、ほとんどのプログラマーが使用できないため、製品品質のAPI内では実際には実行できません。

Scalaにより、アインシュタインがDSLで表現される可能性のあるはるかに優れたAPIを実装できるようになることを期待しています。 ScalaのコアAPIは、すでにこのパスに沿っています。

20
Seth

@ higherkinded テーマに関するプレゼンテーション- Scalaパフォーマンスの考慮事項 これは、Java/Scalaの比較を行います。

ツール:

素晴らしいブログ投稿:

11
oluies

JavaとScalaは両方ともJVMバイトコードにコンパイルされるため、違いはそれほど大きくありません。あなたが得ることができる最良の比較は、おそらく コンピュータ言語ベンチマークゲーム であり、それは本質的にJavaとScalaの両方が同じメモリ使用量を持っていると言います。 Scalaは、リストされているいくつかのベンチマークでJavaよりも遅いわずかですが、それは単にプログラムの実装は異なります。

本当に、彼らは両方ともとても近いので、心配する価値はありません。 Scalaのようなより表現力のある言語を使用することで得られる生産性の向上は、最小限の(もしあれば)パフォーマンスヒット以上の価値があります。

10
ryeguy

Javaの例は、実際の典型的なアプリケーションプログラムのイディオムではありません。このような最適化されたコードは、システムライブラリメソッドで見つけることができます。しかし、その後、正しいタイプの配列、つまりFile []を使用し、IndexOutOfBoundsExceptionをスローしません。 (カウントおよび追加のための異なるフィルター条件)。私のバージョンは(Eclipseで単一のキーを押すために2秒を節約することによって導入されたバグを検索するのに1時間費やすのが好きではないため、常に中括弧で(!)

List<File> bigEnough = new ArrayList<File>();
for(String s : array) {
  if(s.length() > 2) {
    File file = mapping.get(s);
    if (file != null) {
      bigEnough.add(file);
    }
  }
}

しかし、私の現在のプロジェクトから他の多くのugいJavaコード例を紹介することができます。共通の構造と動作を除外することにより、コーディングの一般的なコピーと変更スタイルを回避しようとしました。

私の抽象DAO基本クラスには、一般的なキャッシングメカニズムの抽象内部クラスがあります。具体的なモデルオブジェクトタイプごとに、抽象DAO基本クラスのサブクラスがあります。このサブクラスでは、内部クラスがサブクラス化され、データベースからロードされるときにビジネスオブジェクトを作成するメソッドの実装を提供します。 (独自のAPIを介して別のシステムにアクセスするため、ORMツールは使用できません。)

このサブクラス化とインスタンス化のコードは、Javaではまったく明確ではなく、Scalaでは非常に読みやすくなります。

4
MickH