ConcurrentDictionary陷阱 - 来自GetOrAdd和AddOrUpdate的委托工厂是否同步?注意到AddOrUpdate不是原子的(并且不能保证代理不会多次运行).
我想实现的名称使用并发字典一拉锁定实现这里,但如果字典不应该永远增长,就像这样:
public class ConcurrentDictionaryNamedLocker : INamedLocker
{
// the IntObject values serve as the locks and the counter for how many RunWithLock jobs
// are about to enter or have entered the critical section.
private readonly ConcurrentDictionary<string, IntObject> _lockDict = new ConcurrentDictionary<string, IntObject>();
private static readonly IntObject One = new IntObject(1);
private readonly Func<string, IntObject, IntObject> _decrementFunc = (s, o) => o - 1;
private readonly Func<string, IntObject, IntObject> _incrementFunc = (s, o) => …Run Code Online (Sandbox Code Playgroud) 我想知道Redis的C#客户端比Dictionary/ConcurrentDictionary有什么好处.
我不确定何时使用redis被认为是字典存储的过度杀伤.
谢谢.
我正在使用ConcurrentDictionary通过并行访问来缓存数据,有时新项目可以存储在db中,并且它们不会加载到缓存中.这就是我使用GetOrAdd的原因
public User GetUser(int userId)
{
return _user.GetOrAdd(userId, GetUserFromDb);
}
private User GetUserFromDb(int userId)
{
var user = _unitOfWork.UserRepository.GetById(userId);
// if user is null, it is stored to dictionary
return user;
}
Run Code Online (Sandbox Code Playgroud)
但是,如果用户不为空,我如何检查用户是否从db获取并将用户存储到字典?
可能我可以在GetOrAdd之后立即从ConcurrentDictionary中删除null但它看起来不是线程安全的并且它不是非常优雅的解决方案.无用插入和从字典中删除.你知道怎么做吗?
我正在尝试使用ConcurrentDictionary来帮助完成过滤任务.
如果列表中出现一个数字,那么我想将一个条目从一个字典复制到另一个字典.
但这部分AddOrUpdate不对 - v.Add(number)
我明白了
"无法将类型'void'隐式转换为'System.Collections.Generic.List'
还有两个错误.
class Program
{
static void Main(string[] args)
{
Program p = new Program();
List<int> filter = new List<int> {1,2};
p.Filter(filter);
}
private void Filter(List<int> filter)
{
Dictionary<string, List<int>> unfilteredResults = new Dictionary<string, List<int>>();
unfilteredResults.Add("key1", new List<int> { 1,2,3,4,5});
ConcurrentDictionary<string, List<int>> filteredResults = new ConcurrentDictionary<string, List<int>>();
foreach (KeyValuePair<string, List<int>> unfilteredResult in unfilteredResults)
{
foreach (int number in unfilteredResult.Value)
{
if (filter.Contains(number))
{
filteredResults.AddOrUpdate(unfilteredResult.Key, new List<int> { number }, (k, v) => v.Add(number));
} …Run Code Online (Sandbox Code Playgroud) ConcurrentDictionary.TryUpdate方法需要将comparisonValue与具有指定键的元素的值进行比较.但如果我尝试做这样的事情:
if (!_store.TryGetValue(book.Id, out Book existing))
{
throw new KeyNotFoundException();
}
if (!_store.TryUpdate(book.Id, book, existing))
{
throw new Exception("Unable to update the book");
}
Run Code Online (Sandbox Code Playgroud)
当多个线程同时更新一本书时,它会抛出一个异常,因为existingbook在另一个线程中被更改了.
我不能使用索引器,因为它添加了书,如果它不存在,我不能检查键是否存在,因为它也不会原子.
我改变了我的代码:
while (true)
{
if (!_store.TryGetValue(book.Id, out Book existing))
{
throw new KeyNotFoundException();
}
if (_store.TryUpdate(book.Id, book, existing))
{
break;
}
}
Run Code Online (Sandbox Code Playgroud)
但我担心无限循环.
但是如果我在Update和Delete方法上使用锁定,我将失去使用ConcurrentDictionary的优势.
解决问题的正确方法是什么?
我尝试通过将它包装在BlockingCollection中来实现ConcurrentDictionary,但似乎没有成功.
据我所知,一个变量声明BlockingCollection如工作ConcurrentBag<T>,ConcurrentQueue<T>等等.
因此,要创建一个包含在BlockingCollection中的ConcurrentBag,我会声明并实例化如下:
BlockingCollection<int> bag = new BlockingCollection<int>(new ConcurrentBag<int>());
Run Code Online (Sandbox Code Playgroud)
但如何为ConcurrentDictionary做到这一点?我需要生产者和消费者方面的BlockingCollection的阻止功能.
简单的问题假设我有一个 ConcurrentDictionary
我使用TryAdd和ContainsKey方法
现在假设从100个线程我开始处理东西.假设3个线程在添加新密钥时使用TryAdd方法另外3个线程询问密钥是否存在与ContainsKey方法有关
不要ContainsKey等到那些3个线程返回我结果之前加入的过程?
或者他们没有同步,我的意思是这3个线程中的一个可能正在添加我用ContainsKey方法询问的密钥但是由于该过程尚未完成,我将得到的答案将是假的
Ty非常感谢答案C#WPF .net 4.5最新
This code seems to do a good job of caching async method results. I would like to add some sort of expiration to it. I have tried Tuple but I was not successful in getting it to fully work / compile.
private static readonly ConcurrentDictionary<object, SemaphoreSlim> _keyLocks = new ConcurrentDictionary<object, SemaphoreSlim>();
private static readonly ConcurrentDictionary<object, Tuple<List<UnitDTO>, DateTime>> _cache = new ConcurrentDictionary<object, Tuple<List<UnitDTO>, DateTime>>();
public async Task<string> GetSomethingAsync(string key)
{
string value;
// get the semaphore specific to this key
var …Run Code Online (Sandbox Code Playgroud) 应用程序需要加载数据并缓存一段时间。我希望如果应用程序的多个部分想要同时访问同一个缓存键,缓存应该足够智能,只加载一次数据并将该调用的结果返回给所有调用者。然而,MemoryCache并不是这样做的。如果您并行访问缓存(这通常发生在应用程序中),它会为每次尝试获取缓存值创建一个任务。我认为这段代码会达到预期的结果,但事实并非如此。我希望缓存只运行一项GetDataAsync任务,等待它完成,然后使用结果来获取其他调用的值。
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace ConsoleApp4
{
class Program
{
private const string Key = "1";
private static int number = 0;
static async Task Main(string[] args)
{
var memoryCache = new MemoryCache(new MemoryCacheOptions { });
var tasks = new List<Task>();
tasks.Add(memoryCache.GetOrCreateAsync(Key, (cacheEntry) => GetDataAsync()));
tasks.Add(memoryCache.GetOrCreateAsync(Key, (cacheEntry) => GetDataAsync()));
tasks.Add(memoryCache.GetOrCreateAsync(Key, (cacheEntry) => GetDataAsync()));
await Task.WhenAll(tasks);
Console.WriteLine($"The cached value was: {memoryCache.Get(Key)}");
}
public static async Task<int> GetDataAsync()
{
//Simulate getting a large …Run Code Online (Sandbox Code Playgroud) 我正在对从 TryGet 获得的值执行两次更新,我想知道哪个更好?
选项 1:只锁定价值?
if (HubMemory.AppUsers.TryGetValue(ConID, out OnlineInfo onlineinfo))
{
lock (onlineinfo)
{
onlineinfo.SessionRequestId = 0;
onlineinfo.AudioSessionRequestId = 0;
onlineinfo.VideoSessionRequestId = 0;
}
}
Run Code Online (Sandbox Code Playgroud)
选项 2:锁定整个字典?
if (HubMemory.AppUsers.TryGetValue(ConID, out OnlineInfo onlineinfo))
{
lock (HubMemory.AppUsers)
{
onlineinfo.SessionRequestId = 0;
onlineinfo.AudioSessionRequestId = 0;
onlineinfo.VideoSessionRequestId = 0;
}
}
Run Code Online (Sandbox Code Playgroud) c# ×9
concurrency ×3
dictionary ×3
.net ×2
caching ×1
collections ×1
lambda ×1
memorycache ×1
redis ×1
signalr ×1