目前,我的代碼如下所示:
private List<Node> dirtyNodes = new List<Node> dirtyNodes();
public void UpdateDirtyNodes()
{
while(dirtyNodes.Count > 0)
{
Node nodeToUpdate = dirtyNodes[0];
nodeToUpdate.UpdateNode();
dirtyNodes.Remove(nodeToUpdate);
}
}
public void MarkNodeDirty(Node node)
{
if(!dirtyNodes.Contains(node))
{
dirtyNodes.Add(node);
}
}
public void MarkNodeClean(Node node)
{
dirtyNodes.Remove(node);
}
這是代碼的性能關鍵部分,它比我想要的要慢,因為dirtyNodes.Contains在大多數情況下必須遍歷整個陣列。我想List用 a替換它,HashSet因為它應該更快,但我不知道如何使用UpdateDirtyNodes().
困難在于UpdateNode()可以隨時添加或洗掉節點dirtyNodes,因此while回圈有點尷尬。有沒有辦法從 HashSet 中獲取“第一個”值?順序無關緊要,我只需要留在 while 回圈中直到dirtyNodes為空,更新下一個節點。
我寧愿避免使用 Linq,因為此代碼將是庫的一部分,我不想強??迫它們包含 Linq。
我怎樣才能做到這一點?
uj5u.com熱心網友回復:
事實證明,直接使用列舉器非常容易:
public void UpdateDirtyNodes()
{
while(dirtyNodes.Count > 0)
{
using(HashSet<Node>.Enumerator enumerator = dirtyNodes.GetEnumerator())
{
if(enumerator.MoveNext())
{
Node nodeToUpdate = enumerator.Current;
nodeToUpdate.UpdateNode();
dirtyNodes.Remove(nodeToUpdate);
}
}
}
}
public void MarkNodeDirty(Node node)
{
dirtyNodes.Add(node);
}
我最初嘗試過類似的東西,但沒有完全理解如何手動使用列舉器,但它沒有用。
它明顯快于List(整體幀時間快約 25-50%,具體取決于該更改的情況),所以我很高興。(不要對下面螢屏截圖中的 30MB 分配感到恐慌 - 我正在努力。)

uj5u.com熱心網友回復:
bool dirty在Node類中添加一個欄位。這是保持散列集的補充。然后MarkNodeClean()不需要從 HashSet 中洗掉節點,從而減少了一些 CPU 周期。
如果您覺得在Node類中添加欄位太“臟”(雙關語),那么只需創建一個HashSet<(Node, bool)>而不是HashSet<Node>,但是您會失去分配和垃圾收集額外物件的性能,這并不理想,因為您的代碼是性能 -危急。
UpdateDirtyNodes()將一次獲取一個節點,直到 HashSet 為空。取每個節點后,它會查看布爾標志來決定節點是否實際上是臟的。
PS
你應該dirtyNodes.Clear();從UpdateDirtyNodes(). 這是一個競爭條件。如果在 while 回圈后添加一個節點發現dirtyNodes.Count 為 0,則dirtyNodes.Clear();清除該節點而不對其進行處理。這是一個單獨的錯誤,與您的問題無關。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/351532.html
