7

foreach ループはタイピングを減らし、読みやすくすることに同意します。

ちょっとしたバックアップとして、私は低レイテンシのアプリケーション開発に取り組んでおり、1 秒あたり 100 万パケットを処理する必要があります。100 万個のパケットを繰り返し処理し、この情報をリスナーに送信します。foreach ループを使用して、一連のリスナーを反復処理していました。

プロファイリングを行うと、 foreach ループを実行するために作成されたIterator オブジェクトがたくさんあることがわかりました。foreach ループをインデックス ベースの foreach に変換する no. GC の数を減らし、アプリケーションのスループットを向上させます。

編集:(混乱して申し訳ありませんが、このQをより明確にします)たとえば、リスナーのリスト(固定サイズ)があり、このforloopを1秒間に100万回ループします。foreachはJavaでやり過ぎですか?

例:

for(String s:listOfListeners)
{
   // logic
}

に比べ

for (int i=0;i<listOfListeners.size();i++)
{
   // logic
}

コードのプロファイリングされたスクリーンショット

for (int cnt = 0; cnt < 1_000_000; cnt++)
{
    for (String string : list_of_listeners)
    {
         //No Code here 
    }
}

ここに画像の説明を入力

4

5 に答える 5

10

編集:大きく異なる質問に答える:

たとえば、リスナーのリスト(固定サイズ)があり、このforloopを1秒間に100万回ループします。foreachはJavaでやり過ぎですか?

それは依存します - あなたのプロファイリングは、余分な割り当てが重要であることを実際に示していますか? Java アロケータとガベージ コレクタは、1 秒間に多くの作業を行うことができます。

別の言い方をすれば、手順は次のようになります。

  1. 機能要件とともにパフォーマンス目標を設定する
  2. 機能要件を達成するためにできる限り単純なコードを記述します
  3. そのコードが機能要件を満たしているかどうかを測定する
  4. そうでない場合:
    • 最適化する場所を特定するためのプロファイル
    • 変える
    • テストを再度実行して、意味のあるメトリックに大きな違いがあるかどうかを確認します (割り当てられたオブジェクトの数はおそらく意味のあるメトリックではありません。処理できるリスナーの数はおそらく意味のあるメトリックです)。
    • 手順 3 に戻ります。

おそらくあなたの場合、強化された for ループは重要です。とはいえ、そうであるとは思いませんし、1 秒間に 100 万個のオブジェクトが作成されることが重要であるとは思いません。前後に意味のあるメトリクスを測定します...そして、他のことをする前に具体的なパフォーマンス目標があることを確認します。そうしないと、マイクロ最適化をいつ停止するかがわからないからです。


リストのサイズは、約 100 万個のオブジェクトがストリーミングされます。

したがって、 1 つの反復子オブジェクトを作成していますが、ループ本体を何百万回も実行しています。

プロファイリングを行うと、 foreach ループを実行するために作成された Iterator オブジェクトがたくさんあることがわかりました。

いいえ?1つの反復子オブジェクトのみを作成する必要があります。JLSによると

拡張された for ステートメントは、次の形式の基本的な for ステートメントと同等です。

    for (I #i = Expression.iterator(); #i.hasNext(); ) {
        VariableModifiersopt TargetType Identifier =
            (TargetType) #i.next();
        Statement
    }

ご覧のとおり、これはiterator()メソッドを once呼び出してから、反復ごとにhasNext()andを呼び出します。next()

余分なオブジェクト割り当てが実際にパフォーマンスを大幅に低下させると思いますか?

パフォーマンスよりも読みやすさをどのくらい重視しますか? 私は、パフォーマンスの問題であることが判明するまでは、読みやすさに役立つ拡張 for ループを使用するというアプローチを取ります。私の個人的な経験では、私が書いたものでパフォーマンスが大幅に低下することはありません。それがすべてのアプリケーションに当てはまるとは言えませんが、デフォルトの立場は、可読性の低いコードのみを使用することです。

于 2013-04-10T18:06:26.493 に答える
6

「foreach」ループはIteratorオブジェクトを 1 つだけ作成しますが、2 番目のループは何も作成しません。それぞれ数回しか実行されない非常に多くの個別のループを実行している場合、はい、「foreach」は不必要に高価になる可能性があります。それ以外の場合、これはマイクロ最適化です。

于 2013-04-10T18:07:11.817 に答える
0

この比較は公正ですか?IteratorVsを使用して比較していますget(index)

さらに、各ループは追加の を 1 つだけ作成しますIteratorIterator何らかの理由で 自体が非効率でない限り、同等のパフォーマンスが得られるはずです。

于 2013-04-10T18:08:18.993 に答える
0

ここでの有効性について心配する必要はないと思います。

ほとんどの時間は、実際のアプリケーション ロジックによって消費されます (この場合、ループ内で行うことによって)。

したがって、ここで利便性のために支払う価格については心配しません。

于 2013-04-10T18:07:53.897 に答える