3

汎用コレクションが列挙子をどのように最適化したかを確認するために mscorlib を調べていたところ、次のことがわかりました。

// in List<T>.Enumerator<T>
public bool MoveNext()
{
    List<T> list = this.list;
    if ((this.version == list._version) && (this.index < list._size))
    {
        this.current = list._items[this.index];
        this.index++;
        return true;
    }
    return this.MoveNextRare();
}

スタック サイズは 3 で、バイトコードのサイズは 80 バイトである必要があります。メソッドの名前付けはMoveNextRare私を悩ませ、エラーのケースと空のコレクションのケースが含まれているため、明らかにこれは関心の分離に違反しています。

スタック スペースを最適化し、JIT を支援するために、メソッドがこのように分割されていると仮定しMoveNextます。また、パフォーマンスのボトルネックの一部についても同じことを行いたいと考えていますが、ハード データがなければ、ブードゥー教のプログラミングを貨物に変えたくありません。カルト;)

ありがとう!フロリアン

4

2 に答える 2

3

List<T>.Enumeratorパフォーマンスのために「奇妙な」方法について考える場合は、最初にこれを考慮してください。これは変更可能な structです。恐れずに後ずさりしてください。私は知っています。

最終的に、特定のアプリケーションでどのような違いが生じるかをベンチマーク/プロファイリングせずに、BCL からの最適化を模倣し始めることはありません。BCL には適しているかもしれませんが、あなたには適していません。インストール時に BCL が NGEN に似たサービス全体を通過することを忘れないでください。アプリケーションに何が適切かを知る唯一の方法は、それを測定することです。

あなたは、パフォーマンスのボトルネックについて同じようなことを試したいと言っています。これは、ボトルネックを既に知っていることを示唆しており、何らかの測定が行われていることを示唆しています。したがって、この最適化を試して測定し、パフォーマンスの向上がそれに伴う読みやすさ/メンテナンスの苦痛に見合う価値があるかどうかを確認してください。

何かを試して測定し、そのエビデンスに基づいて決定を下すことは、難しいことではありません。

于 2010-02-17T10:09:06.230 に答える
1

2 つの機能に分けることには、いくつかの利点があります。

メソッドがインライン化される場合、高速パスのみがインライン化され、エラー処理は引き続き関数呼び出しになります。これにより、インライン展開に余分なスペースが必要になるのを防ぎます。しかし、80 バイトの IL はおそらくインライン化のしきい値を超えている可能性があります (以前は 32 バイトとして文書化されていましたが、.NET 2.0 以降に変更されたかどうかはわかりません)。

インライン化されていなくても、関数はより小さくなり、CPU の命令キャッシュ内により簡単に収まります。低速パスが分離されているため、高速パスが存在するたびにキャッシュにフェッチする必要はありません。

CPU 分岐予測子がより一般的なパスを最適化するのに役立つ場合があります (true を返します)。

MoveNextRare は常に false を返すと思いますが、このように構造化することでテール コールになり、private でここからしか呼び出せない場合、JIT は理論的にはこれら 2 つのメソッド間のカスタム呼び出し規約を構築することができます。プロローグもエピローグの重複もない jmp 命令のみ。

于 2010-02-19T22:29:00.630 に答える