이 열거 형 중 하나가 다른 것보다 빠르거나 거의 같은 것입니까? (C에서 # 예)foreach Dictionary <>. Values 또는 List <>를 열거하는 .NET 수집이 더 빠릅니다.
사례 1 :
Dictionary<string, object> valuesDict;
// valuesDict loaded with thousands of objects
foreach (object value in valuesDict.Values) { /* process */ }
케이스 2 :
List<object> valuesList;
// valuesList loaded with thousands of objects
foreach (object value in valuesList) { /* process */ }
UPDATE :
는배경 :
사전은 다른 키잉 검색 유리할 (목록을 반복하는 것과는 대조적으로) iterat라면 이점은 줄어들 것입니다 사전을 통하는 것은 목록을 통과하는 것보다 훨씬 느립니다.
업데이트 : 많은 조언을 듣고 직접 테스트했습니다.
첫째, 결과입니다. 다음은 프로그램입니다.
대하여 반복 전체 컬렉션 딕셔너리 78 Keyd 131 목록 : 76
키 입력 됨 컬렉션 딕셔너리 : 178 Keyd : 194 목록 : 142,800
using System;
using System.Linq;
namespace IterateCollections
{
public class Data
{
public string Id;
public string Text;
}
public class KeyedData : System.Collections.ObjectModel.KeyedCollection<string, Data>
{
protected override string GetKeyForItem(Data item)
{
return item.Id;
}
}
class Program
{
static void Main(string[] args)
{
var dict = new System.Collections.Generic.Dictionary<string, Data>();
var list = new System.Collections.Generic.List<Data>();
var keyd = new KeyedData();
for (int i = 0; i < 10000; i++)
{
string s = i.ToString();
var d = new Data { Id = s, Text = s };
dict.Add(d.Id, d);
list.Add(d);
keyd.Add(d);
}
var sw = new System.Diagnostics.Stopwatch();
sw.Start();
for (int r = 0; r < 1000; r++)
{
foreach (Data d in dict.Values)
{
if (null == d) throw new ApplicationException();
}
}
sw.Stop();
var dictTime = sw.ElapsedMilliseconds;
sw.Reset();
sw.Start();
for (int r = 0; r < 1000; r++)
{
foreach (Data d in keyd)
{
if (null == d) throw new ApplicationException();
}
}
sw.Stop();
var keydTime = sw.ElapsedMilliseconds;
sw.Reset();
sw.Start();
for (int r = 0; r < 1000; r++)
{
foreach (Data d in list)
{
if (null == d) throw new ApplicationException();
}
}
sw.Stop();
var listTime = sw.ElapsedMilliseconds;
Console.WriteLine("Iterate whole collection");
Console.WriteLine("Dict: " + dictTime);
Console.WriteLine("Keyd: " + keydTime);
Console.WriteLine("List: " + listTime);
sw.Reset();
sw.Start();
for (int r = 0; r < 1000; r++)
{
for (int i = 0; i < 10000; i += 10)
{
string s = i.ToString();
Data d = dict[s];
if (null == d) throw new ApplicationException();
}
}
sw.Stop();
dictTime = sw.ElapsedMilliseconds;
sw.Reset();
sw.Start();
for (int r = 0; r < 1000; r++)
{
for (int i = 0; i < 10000; i += 10)
{
string s = i.ToString();
Data d = keyd[s];
if (null == d) throw new ApplicationException();
}
}
sw.Stop();
keydTime = sw.ElapsedMilliseconds;
sw.Reset();
sw.Start();
for (int r = 0; r < 10; r++)
{
for (int i = 0; i < 10000; i += 10)
{
string s = i.ToString();
Data d = list.FirstOrDefault(item => item.Id == s);
if (null == d) throw new ApplicationException();
}
}
sw.Stop();
listTime = sw.ElapsedMilliseconds * 100;
Console.WriteLine("Keyed search collection");
Console.WriteLine("Dict: " + dictTime);
Console.WriteLine("Keyd: " + keydTime);
Console.WriteLine("List: " + listTime);
}
}
}
업데이트 :
@Blam이 제안한 KeyedCollection과 Dictionary의 비교.
가장 빠른 방법은 KeyedCollection 항목의 배열을 반복하는 것입니다.
그러나 사전 값을 반복하는 것이 배열로 변환하지 않고 KeyedCollection보다 더 빠릅니다.
사전 값을 반복하는 것은 사전 컬렉션보다 훨씬 빠르고 빠릅니다.
Iterate 1,000 times over collection of 10,000 items
Dictionary Pair: 519 ms
Dictionary Values: 95 ms
Dict Val ToArray: 92 ms
KeyedCollection: 141 ms
KeyedC. ToArray: 17 ms
타이밍은 Windows 콘솔 응용 프로그램 (릴리스 빌드)에서입니다. 다음은 소스 코드입니다.
using System;
using System.Collections.Generic;
using System.Linq;
namespace IterateCollections
{
public class GUIDkeyCollection : System.Collections.ObjectModel.KeyedCollection<Guid, GUIDkey>
{
// This parameterless constructor calls the base class constructor
// that specifies a dictionary threshold of 0, so that the internal
// dictionary is created as soon as an item is added to the
// collection.
//
public GUIDkeyCollection() : base() { }
// This is the only method that absolutely must be overridden,
// because without it the KeyedCollection cannot extract the
// keys from the items.
//
protected override Guid GetKeyForItem(GUIDkey item)
{
// In this example, the key is the part number.
return item.Key;
}
public GUIDkey[] ToArray()
{
return Items.ToArray();
}
//[Obsolete("Iterate using .ToArray()", true)]
//public new IEnumerator GetEnumerator()
//{
// throw new NotImplementedException("Iterate using .ToArray()");
//}
}
public class GUIDkey : Object
{
private Guid key;
public Guid Key
{
get
{
return key;
}
}
public override bool Equals(Object obj)
{
//Check for null and compare run-time types.
if (obj == null || !(obj is GUIDkey)) return false;
GUIDkey item = (GUIDkey)obj;
return (Key == item.Key);
}
public override int GetHashCode() { return Key.GetHashCode(); }
public GUIDkey(Guid guid)
{
key = guid;
}
}
class Program
{
static void Main(string[] args)
{
const int itemCount = 10000;
const int repetitions = 1000;
const string resultFormat = "{0,18}: {1,5:D} ms";
Console.WriteLine("Iterate {0:N0} times over collection of {1:N0} items", repetitions, itemCount);
var dict = new Dictionary<Guid, GUIDkey>();
var keyd = new GUIDkeyCollection();
for (int i = 0; i < itemCount; i++)
{
var d = new GUIDkey(Guid.NewGuid());
dict.Add(d.Key, d);
keyd.Add(d);
}
var sw = new System.Diagnostics.Stopwatch();
long time;
sw.Reset();
sw.Start();
for (int r = 0; r < repetitions; r++)
{
foreach (KeyValuePair<Guid, GUIDkey> w in dict)
{
if (null == w.Value) throw new ApplicationException();
}
}
sw.Stop();
time = sw.ElapsedMilliseconds;
Console.WriteLine(resultFormat, "Dictionary Pair", time);
sw.Reset();
sw.Start();
for (int r = 0; r < repetitions; r++)
{
foreach (GUIDkey d in dict.Values)
{
if (null == d) throw new ApplicationException();
}
}
sw.Stop();
time = sw.ElapsedMilliseconds;
Console.WriteLine(resultFormat, "Dictionary Values", time);
sw.Reset();
sw.Start();
for (int r = 0; r < repetitions; r++)
{
foreach (GUIDkey d in dict.Values.ToArray())
{
if (null == d) throw new ApplicationException();
}
}
sw.Stop();
time = sw.ElapsedMilliseconds;
Console.WriteLine(resultFormat, "Dict Val ToArray", time);
sw.Reset();
sw.Start();
for (int r = 0; r < repetitions; r++)
{
foreach (GUIDkey d in keyd)
{
if (null == d) throw new ApplicationException();
}
}
sw.Stop();
time = sw.ElapsedMilliseconds;
Console.WriteLine(resultFormat, "KeyedCollection", time);
sw.Reset();
sw.Start();
for (int r = 0; r < repetitions; r++)
{
foreach (GUIDkey d in keyd.ToArray())
{
if (null == d) throw new ApplicationException();
}
}
sw.Stop();
time = sw.ElapsedMilliseconds;
Console.WriteLine(resultFormat, "KeyedC. ToArray", time);
}
}
}
두 번째는 더 빨리, 가장 가능성이, 같은 사전 값이 드문 드문 것 같습니다 여기
는 코드입니다. 구현에 따라 목록 값이 더 좋을 것입니다. – Lucas최적화 된 Linq 쿼리를 사용하지 않는 특별한 이유가 있거나 응용 프로그램의 타이밍을 밀리 세컨드로 줄일 수 있습니까? – Jasper
조기 미세 최적화는 악합니다. – JustAnotherUserYouMayKnow