我正在研究馆藏的表现,我注意到一个奇怪的List行为。首次访问列表的速度比后续访问速度慢得多,这可能与什么有关?
static void Main(string[] args)
{
int k = 1000 * 1000;
List<int> l = new List<int>();
for (int i = 0; i < k; i++)
{
l.Add(i);
}
for (int i = 0; i < 10; i++)
{
var res = With_timer(() => l.IndexOf(0));
}
Console.ReadKey(true);
}
UPD
private static T With_timer<T>(Func<T> action)
{
Stopwatch sw = Stopwatch.StartNew();
var result = action();
sw.Stop();
Console.WriteLine($"TotalMilliseconds: {sw.Elapsed.TotalMilliseconds}");
return result;
}
UPD2 将动作移至其他方法
private static void TestMethod(List<int> l)
{
for (int i = 0; i < 15; i++)
{
var res = With_timer(() => l.IndexOf(i));
}
}
答案 0 :(得分:1)
速度是由于IndexOf
方法和秒表jitted的首次访问所致。您可以修改代码,以使在循环外对这些方法的调用至少执行一次,一旦这样做,记录的访问时间都将保持一致。
static void Main(string[] args)
{
var unrelatedList = new List<int>(1) { 1 };
var jitMe = unrelatedList.IndexOf(1);
var sw = Stopwatch.StartNew();
sw.Stop();
Console.WriteLine($"Initialized {jitMe}, {sw.Elapsed.TotalMilliseconds}");
Console.WriteLine();
const int k = 1000 * 1000;
var l = new List<int>(k);
for (var i = 0; i < k; i++)
{
l.Add(i);
}
for (var i = 0; i < 10; i++)
{
sw = Stopwatch.StartNew();
var itm = l.IndexOf(0);
sw.Stop();
Console.WriteLine($"TotalMilliseconds: {sw.Elapsed.TotalMilliseconds}, {itm}");
}
Console.WriteLine("Done");
Console.ReadLine();
}
输出
Initialized 0, 0.0015
TotalMilliseconds: 0.0005, 0
TotalMilliseconds: 0.0005, 0
TotalMilliseconds: 0.0005, 0
TotalMilliseconds: 0, 0
TotalMilliseconds: 0, 0
TotalMilliseconds: 0.0005, 0
TotalMilliseconds: 0.0005, 0
TotalMilliseconds: 0.0005, 0
TotalMilliseconds: 0.0005, 0
TotalMilliseconds: 0.0005, 0
答案 1 :(得分:0)
可能是正在为后备存储分配新的(初始)数组。 IIRC(已经有一段时间了),列表的后备存储的默认初始大小为10个元素。尝试循环11次而不是10次,看看下一次访问是否需要更多时间,因为它需要分配一个新数组并在幕后复制元素。
— 没关系,重新阅读代码,您正在检查访问权限,而不是插入。 —
您可能还会看到JIT流程的工件。如果将其移至一个单独的方法并多次调用该方法,两次调用中是否会看到类似的结果?
最后,查看doc.getElementsByTagName("a")
语句的计时器结果,或者至少查看访问每个索引的计时器结果,而不是每次查看位置.Add()
,可能会更有趣。