對于以下場景,C# 中最快的迭代技術是什么?
由于我在 c# 中處理基于小型原型的 ECS,因此我想利用快取高效迭代來獲得最大性能。我該怎么做才能使迭代更快并獲得最大的快取命中?
var chunks = archetype.Chunks; // Property that returns a Chunk[] array
for (var chunkIndex = 0; chunkIndex < archetype.Size; chunkIndex ) {
ref var chunk = ref chunks[chunkIndex];
var transforms = chunk.GetArray<Transform>(); // Returns a Transform[] array
var rotations = chunk.GetArray<Rotation>(); // Returns a Rotation[] array
for (var index = 0; index < chunk.Capacity; index ) {
ref var transform = ref transforms[index];
ref var rotation = ref rotations[index];
transform.x ;
rotation.w ;
}
}
細節...
public struct Transform{ float x; float y; }
public struct Rotation{ float x; float y; float z; float w; }
T[] (chunk).GetArray<T>(){
return fittingTightlyPackedManagedArrayForT as T[]; // Pseudocode
}
int (chunk).Capcity{ get; set; } // Just a property of how big each array is in the chunk, all having the same size
我已經測驗了一個不安全的變體來減少邊界檢查,但是根據我的基準測驗,這增加了快取未命中率,并且只是稍微快了一點(不明顯,即使是大量的也不行)。
我還能做些什么來提高迭代速度?很高興收到任何反饋、技術和技巧!:)
uj5u.com熱心網友回復:
陣列或串列上的普通回圈與您在 c# 中進行迭代一樣快,至少除非您有一些編譯器無法使用的特殊知識。編譯器應該識別出您正在回圈陣列,并跳過邊界檢查。并且進行線性迭代應該允許 CPU 在實際需要資料之前預取資料。
在您的示例中,我不確定編譯器是否可以洗掉邊界檢查,因為回圈檢查不針對陣列長度。因此,我至少會嘗試將其更改為陣列上的兩個單獨的回圈。
我不確定為什么不安全版本的快取命中率較低,快取由 CPU 控制,而不是編譯器,我希望不安全版本產生與編譯器非常相似的代碼,至少在記憶體訪問方面.
在某些特殊情況下,手動展開回圈可能很有用,但編譯器應該能夠自動執行此操作,并且這個問題表明它幾乎沒有用。但是編譯器優化可能是善變的,它可能并不總是應用您期望的優化,并且它應用的優化可能在版本之間有所不同,它運行多長時間,如果您應用組態檔引導優化等。
為了獲得任何真正的收益,我會研究SIMD 技術,如果您可以處理更大的資料塊,您可能會獲得一些非常顯著的收益。但收益可能在很大程度上取決于資料的存盤和訪問方式。
在某些情況下,使用陣列結構 (SoA) 方法而不是更常見的結構陣列 (AoS) 可以獲得重大收益。在您的示例中,如果所有x和w值都存盤在單獨的陣列中,您可以只在 128/256/512 位 SIMD 塊中處理整個陣列,這將很難被擊敗。這也具有很高的快取效率,因為您沒有加載任何不必要的位元組。但是使用 SoA 方法可能會對代碼的其他部分產生性能影響。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/518284.html
標籤:C#表现循环迭代不安全
上一篇:Python/Pandas:如何將bs4.element.ResultSet轉換為PandasDataFrame?
下一篇:R中帶有回圈的摘要資料框
