3

Java7のForkJoinPoolクラスには、次のような実装に関するコメントがあります。

メソッド signalWork() と scan() は主なボトルネックであるため、特に大幅にマイクロ最適化/マングルされています。多くのインライン割り当て("while ((local = field) != 0)" の形式) があり、これらは通常、必要な読み取り順序を確保する最も簡単な方法です (これは重要な場合もあります)。

私の質問は次のとおりです:インライン割り当ては読み取り順序にどのように役立ちますか(私はJavaメモリモデルに精通しており、インライン割り当てがここでどのように役立つかわかりません)?

4

2 に答える 2

1

理論的には、インライン化は順序付けに違いはありません。コンパイラーはコードを自由に並べ替えることができます。JIT コンパイラー、場合によっては CPU も同様です。

問題のコードを読んだら、前述の while ループで読み取られるフィールドの多くがvolatileであるという事実に注意を払う必要があります。揮発性の読み取りと書き込みは並べ替えができず、先行発生の関係に従います。揮発性セマンティクスの優れた説明については、このブログ投稿を参照してください。

揮発性読み取りをインライン化することにより、残りの条件は可視性ルールの対象となり、並べ替えの対象になりません。これは、他の手段で達成するのは難しいかもしれません。

于 2013-01-14T19:16:02.510 に答える
1

ninjalj は、式を として安全に書き換えることができるという点で正しいと思いますlocal = field; while (local != 0) {...; local = field }。ただし、実際のコードでは、次のように、はるかに複雑な式が含まれていますwhile ((((e = (int)(c = ctl)) | (u = (int)(c >>> 32))) & (INT_SIGN|SHORT_SIGN)) == (INT_SIGN|SHORT_SIGN) && e >= 0) {それを一連の一時的な変数割り当てと条件文に書き直すと、2 行からコードの半分の画面に変わり、そのような重要なコード コードの 2 つのコピー (ループの前とループ本体の内側) を持つことで、保守性と読みやすさが向上します。悪夢。

関数全体のコード サイズと一時ローカル変数の数も大きくなる可能性があり、パフォーマンスに影響を与えるか、少なくともオプティマイザーの作業が難しくなる可能性があります。インライン化されたバージョンは次のようにコンパイルできますlabel loop_start; calculate condition; if (!condition) goto after_loop; loop_body; goto loop_start; label after_loop;。ループ条件が明示的に 2 回計算されるコードを単独で重複排除するほどコンパイラが常にスマートであるとは思えません。

于 2012-02-22T21:11:58.620 に答える