Jak wspomniał Jim Mischel - nie można wykonać pojedynczego wyszukiwania w celu zmiany wartości elementu słownika. ConcurrentDictionary.AddOrUpdate
sposób zrobić więcej niż jedną operację odnośnika (odbicie źródła):
public TValue AddOrUpdate(TKey key, TValue addValue, Func<TKey, TValue, TValue> updateValueFactory)
{
TValue local2;
if (key == null)
{
throw new ArgumentNullException("key");
}
if (updateValueFactory == null)
{
throw new ArgumentNullException("updateValueFactory");
}
do
{
TValue local3;
while (this.TryGetValue(key, out local3))
{
TValue newValue = updateValueFactory(key, local3);
if (this.TryUpdate(key, newValue, local3))
{
return newValue;
}
}
}
while (!this.TryAddInternal(key, addValue, false, true, out local2));
return local2;
}
zrobiłem testu wydajności przy jednoczesnym słownika i prosty ditcionary:
przedłużenie AddOrUpdate dla IDictionary:
public static class DictionaryExtensions
{
public static void AddOrUpdate<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key, TValue initValue, Func<TKey, TValue, TValue> updateFunc)
{
TValue value;
value = dict.TryGetValue(key, out value) ? updateFunc(key, value) : initValue;
dict[key] = value;
}
}
Test:
static void Main(string[] args)
{
const int dictLength = 100000;
const int testCount = 1000000;
var cdict = new ConcurrentDictionary<string, int>(GetRandomData(dictLength));
var dict = GetRandomData(dictLength).ToDictionary(x => x.Key, x => x.Value);
var stopwatch = new Stopwatch();
stopwatch.Start();
foreach (var pair in GetRandomData(testCount))
cdict.AddOrUpdate(pair.Key, 1, (x, y) => y+1);
stopwatch.Stop();
Console.WriteLine("Concurrent dictionary: {0}", stopwatch.ElapsedMilliseconds);
stopwatch.Reset();
stopwatch.Start();
foreach (var pair in GetRandomData(testCount))
dict.AddOrUpdate(pair.Key, 1, (x, y) => y+1);
stopwatch.Stop();
Console.WriteLine("Dictionary: {0}", stopwatch.ElapsedMilliseconds);
Console.ReadLine();
}
static IEnumerable<KeyValuePair<string, int>> GetRandomData(int count)
{
const int constSeed = 100;
var randGenerator = new Random(constSeed);
return Enumerable.Range(0, count).Select((x, ind) => new KeyValuePair<string, int>(randGenerator.Next().ToString() + "_" + ind, randGenerator.Next()));
}
Wyniki badań moim otoczeniu (MS):
ConcurrentDictionary: 2504
Dictionary: 1351
Próbujesz wyeliminować jedno z wyszukiwań w scenariuszu dodawania lub aktualizacji? – mydogisbox
Równoczesny słownik wydaje się dość wydajny w wielu przypadkach, czy sprawdziłeś, czy zapewnia on wystarczającą wydajność dla twojego scenariusza? – Alex
Czy możesz posortować pary klucz-wartość? Domyślam się, że większość będzie O (n log n), więc być może będziesz musiał przetestować najlepszą wydajność – Carsten