当前位置: 代码网 > it编程>编程语言>Asp.net > C# ConcurrentDictionary的使用小结

C# ConcurrentDictionary的使用小结

2025年12月29日 Asp.net 我要评论
concurrentdictionary<tkey, tvalue> 是 .net 中一个线程安全的字典集合,专为高并发读写场景设计。它是 system.collections.concu

concurrentdictionary<tkey, tvalue> 是 .net 中一个线程安全的字典集合,专为高并发读写场景设计。它是 system.collections.concurrent 命名空间下的核心类型之一,适用于多线程环境中需要高效、安全地共享键值对数据的场景。

✅ 一、为什么需要concurrentdictionary?

普通 dictionary<tkey, tvalue> 不是线程安全的。如果多个线程同时读写:

var dict = new dictionary<string, int>();
// 线程a: dict["a"] = 1;
// 线程b: dict["b"] = 2;
// 可能抛出 invalidoperationexception 或数据损坏!

即使加锁(lock)也能实现线程安全,但会带来性能瓶颈(串行化访问)。

concurrentdictionary

  • 无需外部加锁
  • 内部使用细粒度锁或无锁算法
  • 支持高并发读 + 适度并发写

🧱 二、核心特性

特性说明
线程安全所有公共成员(add、get、remove 等)都是线程安全的
高性能并发读读操作几乎无锁(lock-free),性能接近普通字典
分段/桶式结构内部将数据分片(buckets),减少写冲突
原子操作支持提供 addorupdate, getoradd 等复合原子操作
不保证顺序dictionary 一样,不维护插入顺序

⚠️ 注意:concurrentdictionary 的枚举(foreach)是线程安全的快照,但可能包含“过时”数据(因为其他线程可能正在修改)。

🔧 三、常用 api 与示例

1. 创建

var cache = new concurrentdictionary<string, int>();
// 或指定初始容量和并发级别(高级用法)
var cache2 = new concurrentdictionary<string, int>(concurrencylevel: 4, capacity: 16);

2. 基本操作(线程安全)

// 添加(如果不存在)
cache.tryadd("key1", 100); // 返回 bool

// 获取(如果存在)
if (cache.trygetvalue("key1", out int value))
{
    console.writeline(value); // 100
}

// 更新(如果存在)
cache.tryupdate("key1", 200, 100); // 仅当当前值为100时更新为200

// 删除
cache.tryremove("key1", out int removedvalue);

3. 高级原子操作(⭐ 最常用!)

✅getoradd(key, valuefactory)

如果 key 不存在,则调用工厂方法创建值并添加;否则返回现有值。

var config = cache.getoradd("config", key =>
{
    // 模拟耗时加载(只执行一次!)
    thread.sleep(1000);
    return loadconfigfromdatabase();
});

💡 多个线程同时调用 getoradd("config", ...) 时,工厂方法只会被调用一次(其他线程等待结果),避免重复初始化!

✅addorupdate(key, addvaluefactory, updatevaluefactory)

如果不存在则添加,存在则更新。

// 实现计数器
cache.addorupdate("counter", 
    addvalue: 1,                          // 不存在时设为1
    updatevaluefactory: (key, oldvalue) => oldvalue + 1 // 存在时+1
);

⚖️ 四、与加锁dictionary的性能对比

场景dictionary + lockconcurrentdictionary
高并发读所有读需排队(慢)几乎无锁(快)
低并发写串行写(中等)分段锁(较快)
高并发写严重瓶颈仍优于全局锁
代码简洁性需手动管理锁无需锁,api 更丰富

📊 在典型 web 应用缓存场景(大量读 + 少量写),concurrentdictionary 性能可提升 5~10 倍。

🚫 五、常见误区

❌ 误区 1:认为dict[key] = value是原子的

// 错误!这实际上是:
//   if (exists) update; else add;
// 但中间可能被其他线程干扰
cache["key"] = newvalue; // 不是原子操作!

✅ 正确做法:

cache.addorupdate("key", newvalue, (k, old) => newvalue);

❌ 误区 2:在getoradd中做非幂等操作

// 危险!工厂方法可能被多次调用(虽然最终只存一个结果)
var obj = cache.getoradd("key", k => new expensiveobject()); // ok

// 更危险:有副作用的操作
cache.getoradd("key", k => 
{
    log("creating instance"); // 可能被记录多次!
    return new myservice();
});

💡 虽然最终值是唯一的,但工厂方法可能被多个线程同时调用(.net 6+ 已优化为单次调用,但旧版本不一定)。建议工厂方法无副作用、幂等

🛠 六、典型应用场景

1.内存缓存(cache)

public class inmemorycache
{
    private readonly concurrentdictionary<string, object> _cache = new();

    public t getorcreate<t>(string key, func<t> factory)
    {
        return (t)_cache.getoradd(key, k => factory());
    }
}

2.计数器 / 统计

private readonly concurrentdictionary<string, int> _hitcounts = new();

public void recordhit(string page)
{
    _hitcounts.addorupdate(page, 1, (k, v) => v + 1);
}

3.对象池(object pool)

private readonly concurrentdictionary<type, stack<object>> _pools = new();

public object rent(type type)
{
    var pool = _pools.getoradd(type, t => new stack<object>());
    return pool.trypop(out var obj) ? obj : activator.createinstance(type);
}

📏 七、性能调优建议

参数说明
concurrencylevel预期并发更新线程数(默认为 cpu 核心数)
capacity初始容量(避免频繁扩容)
// 预期 8 个线程并发写,初始存 1000 项
var dict = new concurrentdictionary<string, data>(
    concurrencylevel: 8,
    capacity: 1000
);

💡 大多数场景用默认构造函数即可,除非你有明确的性能测试数据。

✅ 总结:何时使用concurrentdictionary?

场景推荐
多线程读写共享字典✅ 强烈推荐
高频读 + 低频写(如缓存)✅ 最佳选择
需要原子“获取或创建”语义✅ 必选
单线程或只读场景❌ 用普通 dictionary 更轻量
需要保持插入顺序❌ 考虑 immutabledictionary 或加锁的 sorteddictionary

🔑 记住:concurrentdictionary 不是万能的,但它是在并发字典场景下最高效、最安全的选择。

到此这篇关于c# concurrentdictionary的使用小结的文章就介绍到这了,更多相关c# concurrentdictionary内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com