パフォーマンスが重要なバイナリ決定ツリーがあり、この質問を1行のコードに集中したいと思います。バイナリツリーイテレータのコードは、それに対してパフォーマンス分析を実行した結果です。
        public ScTreeNode GetNodeForState(int rootIndex, float[] inputs)
        {
0.2%        ScTreeNode node = RootNodes[rootIndex].TreeNode;
24.6%       while (node.BranchData != null)
            {
0.2%            BranchNodeData b = node.BranchData;
0.5%            node = b.Child2;
12.8%           if (inputs[b.SplitInputIndex] <= b.SplitValue)
0.8%                node = b.Child1;
            }
0.4%        return node;
        }BranchDataはフィールドであり、プロパティではありません。インライン化されないリスクを防ぐためにこれを行いました。
BranchNodeDataクラスは次のとおりです。
public sealed class BranchNodeData
{
    /// <summary>
    /// The index of the data item in the input array on which we need to split
    /// </summary>
    internal int SplitInputIndex = 0;
    /// <summary>
    /// The value that we should split on
    /// </summary>
    internal float SplitValue = 0;
    /// <summary>
    /// The nodes children
    /// </summary>
    internal ScTreeNode Child1;
    internal ScTreeNode Child2;
}ご覧のように、whileループ/ nullチェックはパフォーマンスに大きな影響を与えます。木が大きいので、葉を探すのに時間がかかると思いますが、その一行に費やされた時間の偏りを知りたいです。
私はもう試した:
- ヌルチェックを分離する-ヒットとなるのはヌルチェックです。
- オブジェクトにブールフィールドを追加し、それをチェックしても、違いはありませんでした。何を比較するかは関係ありません。問題なのは比較です。
これは分岐予測の問題ですか?もしそうなら、私はそれについて何ができますか?どちらかと言えば?
CILを理解するつもりはありませんが、CILから情報を取得できるように、誰にでも公開するつもりです。
.method public hidebysig
instance class OptimalTreeSearch.ScTreeNode GetNodeForState (
    int32 rootIndex,
    float32[] inputs
) cil managed
{
    // Method begins at RVA 0x2dc8
    // Code size 67 (0x43)
    .maxstack 2
    .locals init (
        [0] class OptimalTreeSearch.ScTreeNode node,
        [1] class OptimalTreeSearch.BranchNodeData b
    )
    IL_0000: ldarg.0
    IL_0001: ldfld class [mscorlib]System.Collections.Generic.List`1<class OptimalTreeSearch.ScRootNode> OptimalTreeSearch.ScSearchTree::RootNodes
    IL_0006: ldarg.1
    IL_0007: callvirt instance !0 class [mscorlib]System.Collections.Generic.List`1<class OptimalTreeSearch.ScRootNode>::get_Item(int32)
    IL_000c: ldfld class OptimalTreeSearch.ScTreeNode OptimalTreeSearch.ScRootNode::TreeNode
    IL_0011: stloc.0
    IL_0012: br.s IL_0039
    // loop start (head: IL_0039)
        IL_0014: ldloc.0
        IL_0015: ldfld class OptimalTreeSearch.BranchNodeData OptimalTreeSearch.ScTreeNode::BranchData
        IL_001a: stloc.1
        IL_001b: ldloc.1
        IL_001c: ldfld class OptimalTreeSearch.ScTreeNode OptimalTreeSearch.BranchNodeData::Child2
        IL_0021: stloc.0
        IL_0022: ldarg.2
        IL_0023: ldloc.1
        IL_0024: ldfld int32 OptimalTreeSearch.BranchNodeData::SplitInputIndex
        IL_0029: ldelem.r4
        IL_002a: ldloc.1
        IL_002b: ldfld float32 OptimalTreeSearch.BranchNodeData::SplitValue
        IL_0030: bgt.un.s IL_0039
        IL_0032: ldloc.1
        IL_0033: ldfld class OptimalTreeSearch.ScTreeNode OptimalTreeSearch.BranchNodeData::Child1
        IL_0038: stloc.0
        IL_0039: ldloc.0
        IL_003a: ldfld class OptimalTreeSearch.BranchNodeData OptimalTreeSearch.ScTreeNode::BranchData
        IL_003f: brtrue.s IL_0014
    // end loop
    IL_0041: ldloc.0
    IL_0042: ret
} // end of method ScSearchTree::GetNodeForState編集:私は分岐予測テストを行うことにしました、もししばらくの間であれば同一のものを追加したので、
while (node.BranchData != null)そして
if (node.BranchData != null)その中に。次に、それに対してパフォーマンス分析を実行しました。最初の比較の実行には、常にtrueを返す2番目の比較の実行に比べて6倍の時間がかかりました。だから、それは確かに分岐予測の問題のように見えます-そして、私はそれについて私が何もすることができないと思いますか?!
別の編集
上記の結果は、whileチェックのためにnode.BranchDataをRAMからロードする必要がある場合にも発生し、ifステートメント用にキャッシュされます。
これは、同様のトピックに関する3番目の質問です。今回は1行のコードに注目します。この問題に関する他の質問は次のとおりです。
while(true) { /* current body */ if(node.BranchData == null) return node; }。何か変化はありますか?
                while(true) { BranchNodeData b = node.BranchData; if(ReferenceEquals(b, null)) return node; node = b.Child2; if (inputs[b.SplitInputIndex] <= b.SplitValue) node = b.Child1; }これはnode. BranchData一度だけ取得します。
                
BranchNodeプロパティの実装を示してください。交換してみてくださいnode.BranchData != nullReferenceEquals(node.BranchData, null)。違いはありますか?