【问题标题】:Can I simplify my ConcurrentDictionary "add or update" method? [closed]我可以简化我的 ConcurrentDictionary “添加或更新”方法吗? [关闭]
【发布时间】:2020-11-04 20:12:03
【问题描述】:

我有这样的代码:

public ConcurrentDictionary<Guid, DeviceItem> deviceStatesCache = new ConcurrentDictionary<Guid, DeviceItem>();
private readonly object deviceStatesCacheLock = new object();

public void StoreDeviceStateInCache(Guid guid, DeviceItem deviceState) 
{
        bool added, removed, updated = false;
        
        lock (deviceStatesCacheLock)
        { 
            added = deviceStatesCache.TryAdd(guid, deviceState);

            if (!added) {
                removed = deviceStatesCache.TryRemove(guid, out var _);
                if (removed)
                { 
                    updated = deviceStatesCache.TryAdd(guid, deviceState);
                }
            }
        }

        if (!updated) 
            throw new Exception("WTF: cannot update deviceStatesCache!");
}

private QueryDevicesResponse CreateQueryDevicesResponse()
{
        var deviceItems = new List<DeviceItem>();

        lock (deviceStatesCacheLock)
        {
            foreach (var item in deviceStatesCache)
            {
                deviceItems.Add(item.Value);
            }
        }

        var response = new QueryDevicesResponse()
        {
            eventData = new QueryDevicesResponse.EventData()
            {
                devices = deviceItems
            }
        };

        // response.eventSourceGuid = Guid.Empty.ToString();

        return response;
}

(编辑)

我的lock 应该在以下情况下工作:

  1. 当另一个线程尝试在StoreDeviceStateInCache 方法中的删除和插入之间获取值时(只有这个)。

  2. 当另一个线程开始读取CreateQueryDevicesResponse() 方法中的所有项目时。

我可以简化一下StoreDeviceStateInCache() 方法吗?

我知道存在 AddOrUpdate 方法,但我觉得它没有帮助,因为我必须定义额外的方法,而且这看起来比我的代码可读性差。

看起来Michael Liu suggestiondeviceStatesCache[guid] = deviceState; 应该足够了

我可以稍微简化CreateQueryDevicesResponse() 方法并“原子地”阅读完整的字典吗?

(当然,WTF 代表“多么可怕的失败”类型的例外)

【问题讨论】:

  • 请准确说明您的操作应该做什么,以及您的目标是哪种线程安全。
  • 简化代码的一种方法是将ConcurrentDictionary 替换为普通的Dictionary。如果您必须锁定 any ConcurrentDictionary 的成员,那么您必须锁定 all 他们(否则它将不是线程安全的) .在这种情况下,ConcurrentDictionary 的所有优点都消失了,而你只剩下它的缺点(不方便的 API 和同步开销)。

标签: c# .net concurrentdictionary


【解决方案1】:

如果我对您的代码的理解正确,您想在键不存在时添加字典条目,如果键存在则替换字典条目。

您可以通过使用 ConcurrentDictionary 的索引器来完成此操作,而无需任何额外的锁定:

deviceStatesCache[guid] = deviceState;

【讨论】:

    【解决方案2】:

    您也可以使用 ConcurrentDictionary 类型的 AddOrUpdate 方法来实现这一点。像下面的东西

    deviceStatesCache.AddOrUpdate(guid, deviceState, (key, value) => deviceState);

    【讨论】:

    • 你能从你的例子中解释一下我应该在keyvalue 中添加什么吗?
    • @Kamil: keyvalue 只是 lambda 参数的任意名称,在这种情况下其值未使用。当 ConcurrentDictionary 调用 lambda 时,它将分别传递 guid 的值和 deviceStatesCache[guid] 的现有值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-23
    • 2010-09-10
    • 2014-11-22
    相关资源
    最近更新 更多