从字典中复制引用到对象还是直接从字典中访问对象更快?
本文关键字:对象 字典 访问 复制 引用 | 更新日期: 2023-09-27 18:04:00
问题很简单
这个代码是
public Dictionary<string, SomeObject> values = new Dictionary<string, SomeObject>();
void Function()
{
values["foo"].a = "bar a";
values["foo"].b = "bar b";
values["foo"].c = "bar c";
values["foo"].d = "bar d";
}
和下面的代码一样快
public Dictionary<string, SomeObject> values = new Dictionary<string, SomeObject>();
void Function()
{
var someObject = values["foo"];
someObject.a = "bar a";
someObject.b = "bar b";
someObject.c = "bar c";
someObject.d = "bar d";
}
常识告诉我,在字典中查找一次引用并将其存储在某个地方应该更快,这样就不需要多次查找,但我真的不知道字典是如何工作的。
那么它是否更快呢?,为什么?
是的,你是正确的。第一种方法查找字典4次,而第二种方法只查找一次。第二种肯定更好。
然而,在现实生活中,字典查找是非常快的,所以除非你有一个庞大的字典,否则差异不会被注意到,甚至可能无法测量。
Joe是绝对正确的,但似乎这还不够,我做了一个简单的明显的测试:
static void Main(string[] args)
{
var dict = new Dictionary<string, Foo>();
var number = 10000000;
for (int i = 0; i < number; i++)
{
dict[i.ToString()] = new Foo();
}
var watch = new Stopwatch();
watch.Start();
for (int i = 0; i < number; i++)
{
var key = i.ToString();
dict[key].A = "a";
dict[key].B = "b";
dict[key].C = "c";
dict[key].D = "d";
}
watch.Stop();
Console.Out.WriteLine(watch.ElapsedMilliseconds);
watch.Reset();
watch.Start();
for (int i = 0; i < number; i++)
{
var key = i.ToString();
var foo = dict[key];
foo.A = "a";
foo.B = "b";
foo.C = "c";
foo.D = "d";
}
watch.Stop();
Console.Out.WriteLine(watch.ElapsedMilliseconds);
}
class Foo
{
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
public string D { get; set; }
}
在我的机器上,输出为:
3423
2113
Press any key to continue . . .
只有1次查找绝对减少了大数的总时间。
我很好奇。下面的单元测试(可能)显示第二种方法大约快25%。(121 ms vs 91 ms)。从6个字段到2个字段缩小了差距,40毫秒vs 33毫秒。我说可能是因为我写得很快,我不相信它对测量一些副作用是免疫的,但它显示了预期的行为,所以为什么要质疑它。(哈)。
using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Diagnostics;
namespace TestProject1
{
public class DataObject
{
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
public string D { get; set; }
public string E { get; set; }
public string F { get; set; }
}
[TestClass]
public class UnitTest1
{
public static Dictionary<string, DataObject> dict = new Dictionary<string, DataObject>();
static string lookie;
[ClassInitialize()]
public static void MyClassInitialize(TestContext testContext) {
Random rand = new Random(123545);
for (int i = 0; i < 10000; i++)
{
string key = rand.NextDouble().ToString();
DataObject dob = new DataObject();
dict.Add(key, dob);
if (i == 4567)
lookie = key;
}
}
[TestMethod]
public void TestMethod()
{
Stopwatch sw = new Stopwatch();
sw.Start();
for (int j = 0; j < 100000; j++)
{
dict[lookie].A = "val" + j;
dict[lookie].B = "val" + j;
dict[lookie].C = "val" + j;
dict[lookie].D = "val" + j;
dict[lookie].E = "val" + j;
dict[lookie].F = "val" + j;
}
sw.Stop();
System.Diagnostics.Debug.WriteLine(sw.ElapsedMilliseconds);
sw.Reset();
sw.Start();
for (int j = 0; j < 100000; j++)
{
DataObject dob = dict[lookie];
dob.A = "val" + j;
dob.B = "val" + j;
dob.C = "val" + j;
dob.D = "val" + j;
dob.E = "val" +j;
dob.F = "val" +j;
}
sw.Stop();
System.Diagnostics.Debug.WriteLine(sw.ElapsedMilliseconds);
}
}
}