从‘Hello World’到高并发:用C# Concurrent集合搞定多线程数据共享
第一次在C#中遇到多线程数据共享问题时,我盯着屏幕上那个诡异的NullReferenceException发了半小时呆——明明单线程测试一切正常,为什么一开多线程就崩溃?这个经历让我意识到,从单线程思维到并发编程的跨越,远不止是Task.Run()那么简单。本文将带你从零构建一个真实的后台任务处理系统,逐步揭示传统集合在多线程环境中的陷阱,以及如何用System.Collections.Concurrent命名空间下的神器(特别是ConcurrentBag和ConcurrentDictionary)优雅解决这些问题。
1. 为什么我们需要线程安全集合?
假设你正在开发一个电商促销系统,需要实时统计来自全国各地的秒杀请求。单线程版本简单直接:
var requestCounts = new Dictionary<string, int>();
void ProcessRequest(string region)
{
if (!requestCounts.ContainsKey(region))
requestCounts[region] = 0;
requestCounts[region]++;
}
这段代码在单线程环境下完美运行,但当我们尝试用并行处理提升性能时:
Parallel.For(0, 1000, _ => ProcessRequest("华东"));
Console.WriteLine(requestCounts["华东"]); // 输出可能小于1000!
三个致命问题会突然出现:
- 丢失更新:多个线程同时执行
requestCounts[region]++时,增量操作可能被覆盖 - 键值竞争:
ContainsKey检查和后续赋值不是原子操作 - 状态损坏:内部数据结构可能因并发修改而崩溃
传统解决方案是使用lock:
private static readonly object _lock = new object();
void ProcessRequestSafe(string region)
{
lock (_lock) {
if (!requestCounts.ContainsKey(region))
requestCounts[re

搞定多线程数据共享&spm=1001.2101.3001.5002&articleId=160076884&d=1&t=3&u=04e499ea502147379c540c12b8952a41)
669

被折叠的 条评论
为什么被折叠?



