الگویی برای مدیریت دسترسی همزمان به ConcurrentDictionary
نویسنده: وحید نصیری
تاریخ: ۱۳۹۶/۱۰/۱۹ ۱۰:۱۰
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory);
var dictionary = new ConcurrentDictionary<string, string>();
var value = dictionary.GetOrAdd("key1", x => "item 1");
Console.WriteLine(value);
value = dictionary.GetOrAdd("key1", x => "item 2");
Console.WriteLine(value); item 1 item 1
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
namespace Sample
{
class Program
{
static void Main(string[] args)
{
var dictionary = new ConcurrentDictionary<int, int>();
var options = new ParallelOptions { MaxDegreeOfParallelism = 100 };
var addStack = new ConcurrentStack<int>();
Parallel.For(1, 1000, options, i =>
{
var key = i % 10;
dictionary.GetOrAdd(key, k =>
{
addStack.Push(k);
return i;
});
});
Console.WriteLine($"dictionary.Count: {dictionary.Count}");
Console.WriteLine($"addStack.Count: {addStack.Count}");
}
}
} dictionary.Count: 10 addStack.Count: 13
// 'GetOrAdd' call on the dictionary is not thread safe and we might end up creating the pipeline more // once. To prevent this Lazy<> is used. In the worst case multiple Lazy<> objects are created for multiple // threads but only one of the objects succeeds in creating a pipeline. private readonly ConcurrentDictionary<Type, Lazy<RequestDelegate>> _pipelinesCache = new ConcurrentDictionary<Type, Lazy<RequestDelegate>>();
namespace Sample
{
class Program
{
static void Main(string[] args)
{
var dictionary = new ConcurrentDictionary<int, Lazy<int>>();
var options = new ParallelOptions { MaxDegreeOfParallelism = 100 };
var addStack = new ConcurrentStack<int>();
Parallel.For(1, 1000, options, i =>
{
var key = i % 10;
dictionary.GetOrAdd(key, k => new Lazy<int>(() =>
{
addStack.Push(k);
return i;
}));
});
// Access the dictionary values to create lazy values.
foreach (var pair in dictionary)
Console.WriteLine(pair.Value.Value);
Console.WriteLine($"dictionary.Count: {dictionary.Count}");
Console.WriteLine($"addStack.Count: {addStack.Count}");
}
}
} 10 1 2 3 4 5 6 7 8 9 dictionary.Count: 10 addStack.Count: 10
public class LazyConcurrentDictionary<TKey, TValue>
{
private readonly ConcurrentDictionary<TKey, Lazy<TValue>> _concurrentDictionary;
public LazyConcurrentDictionary()
{
_concurrentDictionary = new ConcurrentDictionary<TKey, Lazy<TValue>>();
}
public TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory)
{
var lazyResult = _concurrentDictionary.GetOrAdd(key,
k => new Lazy<TValue>(() => valueFactory(k), LazyThreadSafetyMode.ExecutionAndPublication));
return lazyResult.Value;
}
} public class LockFilter : ActionFilterAttribute
{
static ConcurrentDictionary<StringBuilder, int> _properties;
static LockFilter()
{
_properties = new ConcurrentDictionary<StringBuilder, int>();
}
public int Duration { get; set; }
public string VaryByParam { get; set; }
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var actionArguments = context.ActionArguments.Values.Single();
var properties = VaryByParam.Split(",").ToList();
StringBuilder key = new StringBuilder();
foreach (var actionArgument in actionArguments.GetType().GetProperties())
{
if (!properties.Any(t => t.Trim().ToLower() == actionArgument.Name.ToLower()))
continue;
var value = actionArguments.GetType().GetProperty(actionArgument.Name).GetValue(actionArguments, null).ToString();
key.Append(value);
}
_properties.AddOrUpdate(key, 1, (x, y) => y + 1);
// rest of code
}
} var result = _properties.AddOrUpdate(key
k =>
{
Console.WriteLine("AddValueFactory called for " + k);
return new Lazy<int>(() => 1);
},
(x, y) =>
{
Console.WriteLine("updateValueFactory called for " + key);
return new Lazy<int>(() => y.Value + 1);
}).Value; using System;
using System.Collections.Concurrent;
using System.Threading;
namespace LazyDic
{
public class LazyConcurrentDictionary<TKey, TValue>
{
private readonly ConcurrentDictionary<TKey, Lazy<TValue>> _concurrentDictionary;
public LazyConcurrentDictionary()
{
_concurrentDictionary = new ConcurrentDictionary<TKey, Lazy<TValue>>();
}
public TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory)
{
var lazyResult = _concurrentDictionary.GetOrAdd(key,
k => new Lazy<TValue>(() => valueFactory(k), LazyThreadSafetyMode.ExecutionAndPublication));
return lazyResult.Value;
}
public TValue AddOrUpdate(TKey key, TValue addValue, Func<TKey, TValue, TValue> updateValueFactory)
{
var lazyResult = _concurrentDictionary.AddOrUpdate(
key,
new Lazy<TValue>(() => addValue),
(k, currentValue) => new Lazy<TValue>(() => updateValueFactory(k, currentValue.Value),
LazyThreadSafetyMode.ExecutionAndPublication));
return lazyResult.Value;
}
public TValue AddOrUpdate(TKey key, Func<TKey, TValue> addValueFactory, Func<TKey, TValue, TValue> updateValueFactory)
{
var lazyResult = _concurrentDictionary.AddOrUpdate(
key,
k => new Lazy<TValue>(() => addValueFactory(k)),
(k, currentValue) => new Lazy<TValue>(() => updateValueFactory(k, currentValue.Value),
LazyThreadSafetyMode.ExecutionAndPublication));
return lazyResult.Value;
}
public int Count => _concurrentDictionary.Count;
}
}
var sb1 = new StringBuilder("Food");
var sb2 = new StringBuilder("Food");
Console.WriteLine(sb1 == sb2); true if this instance and sb have equal string, Capacity, and MaxCapacity values; otherwise, false.
public static class ConcurrentDictionaryExtensions
{
public static TValue GetOrAdd<TKey, TValue>(
this ConcurrentDictionary<TKey, Lazy<TValue>> @this,
TKey key, Func<TKey, TValue> valueFactory
)
{
return @this.GetOrAdd(key,
(k) => new Lazy<TValue>(() => valueFactory(k))
).Value;
}
public static TValue AddOrUpdate<TKey, TValue>(
this ConcurrentDictionary<TKey, Lazy<TValue>> @this,
TKey key, Func<TKey, TValue> addValueFactory,
Func<TKey, TValue, TValue> updateValueFactory
)
{
return @this.AddOrUpdate(key,
(k) => new Lazy<TValue>(() => addValueFactory(k)),
(k, currentValue) => new Lazy<TValue>(
() => updateValueFactory(k, currentValue.Value)
)
).Value;
}
public static bool TryGetValue<TKey, TValue>(
this ConcurrentDictionary<TKey, Lazy<TValue>> @this,
TKey key, out TValue value
)
{
value = default(TValue);
var result = @this.TryGetValue(key, out Lazy<TValue> v);
if (result) value = v.Value;
return result;
}
// this overload may not make sense to use when you want to avoid
// the construction of the value when it isn't needed
public static bool TryAdd<TKey, TValue>(
this ConcurrentDictionary<TKey, Lazy<TValue>> @this,
TKey key, TValue value
)
{
return @this.TryAdd(key, new Lazy<TValue>(() => value));
}
public static bool TryAdd<TKey, TValue>(
this ConcurrentDictionary<TKey, Lazy<TValue>> @this,
TKey key, Func<TKey, TValue> valueFactory
)
{
return @this.TryAdd(key,
new Lazy<TValue>(() => valueFactory(key))
);
}
public static bool TryRemove<TKey, TValue>(
this ConcurrentDictionary<TKey, Lazy<TValue>> @this,
TKey key, out TValue value
)
{
value = default(TValue);
if (@this.TryRemove(key, out Lazy<TValue> v))
{
value = v.Value;
return true;
}
return false;
}
public static bool TryUpdate<TKey, TValue>(
this ConcurrentDictionary<TKey, Lazy<TValue>> @this,
TKey key, Func<TKey, TValue, TValue> updateValueFactory
)
{
if (!@this.TryGetValue(key, out Lazy<TValue> existingValue))
return false;
return @this.TryUpdate(key,
new Lazy<TValue>(
() => updateValueFactory(key, existingValue.Value)
),
existingValue
);
}
}