![](/img/trans.png)
[英]Why can't I write if (object is HashSet<>) but it's okay if I write (object.GetType() == typeof(HashSet<>))
[英]How can I reliably test/benchmark the size (including empty buckets) of a .Net HashSet<T> object?
作為個人教育和實驗中的一項練習 ,我想創建自己的HashTable
類。 具體來說,我想編寫該對象,而不使用任何現有代碼(即,該對象將不會從另一個類繼承),而是為了測試目的而映射到現有接口。
由於我打算用C#編寫代碼,因此我的“基准”將是.Net HashSet<T>
類。 我可以輕松地針對添加,刪除和查找請求的執行時間進行測試,但是我不知道如何測試HashSet
基准對象的大小, 包括將來用於添加請求的所有存儲桶都為空 。
當HashSet<t>
對象動態增長以為將來的插入騰出空間時,如何跟蹤它的大小?
需要明確的是,我不需要知道確切的字節數(我知道.Net框架使得很難獲得許多類型的對象的確切大小),但是我寧願知道如何我執行各種類型的測試時,正在使用許多存儲桶,有多少存儲桶正在等待使用。
獲取桶的數量和大小的最佳方法是使用反射。 唯一的麻煩是您需要首先了解集合的行為。 稍微閱讀一下代碼並進行一些嘗試和錯誤之后,似乎您需要計算私有m_buckets
數組的大小以獲取存儲桶數,並計算大於0的值的數目以獲取已使用存儲桶的數。 該方法如下所示:
static void CountBuckets<T>(HashSet<T> hashSet)
{
var field = typeof(HashSet<T>).GetField("m_buckets", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
var buckets = (int[])field.GetValue(hashSet);
int numberOfBuckets = 0;
int numberOfBucketsUsed = 0;
if (buckets != null)
{
numberOfBuckets = buckets.Length;
numberOfBucketsUsed = buckets.Where(i => i != 0).Count();
}
Console.WriteLine("Number of buckets: {0} / Used: {1}", numberOfBuckets, numberOfBucketsUsed);
}
為了測試它,我首先創建了一個自定義類,可以在其中手動設置哈希碼:
public class Hash
{
private readonly int hashCode;
public Hash(int hashCode)
{
this.hashCode = hashCode;
}
public override int GetHashCode()
{
return this.hashCode;
}
}
從那里,我做了一些測試:
var hashSet = new HashSet<Hash>();
CountBuckets(hashSet);
// Number of buckets: 0 / Used: 0
var firstHash = new Hash(0);
hashSet.Add(firstHash);
CountBuckets(hashSet);
// Number of buckets: 3 / Used: 1
hashSet.Add(new Hash(1));
hashSet.Add(new Hash(2));
CountBuckets(hashSet);
// Number of buckets: 3 / Used: 3
hashSet.Add(new Hash(3));
CountBuckets(hashSet);
// Number of buckets: 7 / Used: 4
hashSet.Add(new Hash(1));
CountBuckets(hashSet);
// Number of buckets: 7 / Used: 4
hashSet.Remove(firstHash);
CountBuckets(hashSet);
// Number of buckets: 7 / Used: 3
這聽起來與直觀行為一致。 首先,存儲桶的數量為0。添加一個元素后,其數量將擴展為3。存儲桶的數量保持穩定,直到添加了第四個元素,並將計數擴展為7。在模擬哈希沖突時,已使用存儲桶的數量保持不變如預期的那樣穩定。 刪除元素會減少使用的存儲桶數量。
我對HashSet
內部不是很熟悉,但是您可以看到其來源並使用Reflection獲取其內部值:
HashSet<int> hashSet = new HashSet<int>();
var countField = typeof(HashSet<int>).GetField("m_count", BindingFlags.NonPublic | BindingFlags.Instance);
var freeListField = typeof(HashSet<int>).GetField("m_freeList", BindingFlags.NonPublic | BindingFlags.Instance);
var count = countField.GetValue(hashSet);
var freeList = freeListField.GetValue(hashSet);
注意:這種對私有成員訪問權限的侵犯當然非常丑陋,但是我認為在您的開發/測試階段可以接受。
這是一個有趣的問題強文本...我對你有個根本性的建議:
啟動您的應用程序並獲取內存的大小,然后再初始化HashSet。 您可以使用Process.GetCurrentProcess()。WorkingSet64 (在msdn上: http : //msdn.microsoft.com/zh-cn/library/system.diagnostics.process.workingset64 (v = vs.110 ) .aspx )上進行操作
然后填充您的HashSet並再次打印Process.GetCurrentProcess()。WorkingSet64。 不同之處在於您要尋找的尺寸。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.