2026/3/11 2:02:33
网站建设
项目流程
网站做的好不好看什么,wordpress建立手机网站,宝塔wordpress加速,自己做的网站怎么加搜索功能简介
ConcurrentBagT 是 System.Collections.Concurrent 命名空间下的线程安全的无序集合#xff0c;专为 “多线程同时添加 / 移除元素” 设计#xff0c;核心特点是基于线程局部存储#xff08;TLS#xff09;优化#xff0c;在 “同一线程频繁添加和移除元素”…简介ConcurrentBagT是System.Collections.Concurrent命名空间下的线程安全的无序集合专为 “多线程同时添加 / 移除元素” 设计核心特点是基于线程局部存储TLS优化在 “同一线程频繁添加和移除元素” 的场景下性能最优是.NET中处理无序线程安全集合的核心工具。核心定位与价值在多线程场景中普通的ListT非线程安全多线程操作会抛出异常或数据损坏而lock包裹的ListT存在锁竞争问题性能低。ConcurrentBagT的核心价值无锁核心路径通过线程局部存储TLS让每个线程优先操作自己的私有数据段减少跨线程锁竞争无序存储不保证元素的顺序插入顺序≠遍历顺序牺牲顺序换取性能线程安全所有操作Add/TryTake等均线程安全无需手动加锁适配特定场景尤其适合 “生产者和消费者为同一线程” 的场景如线程池线程自产自销。核心特点特性ConcurrentBagConcurrentQueueConcurrentStack典型使用场景顺序保证无序完全不保证FIFOLIFO不关心顺序的场景线程安全是是是多线程并发元素重复取出风险可能同一个线程可能先取后放不可能不可能允许“偷取”工作内存使用较低分段 线程本地袋中等中等大量小对象支持 Peek不支持支持支持—典型模式工作窃取work-stealing生产者-消费者后进先出任务栈并行任务池、负载均衡内部实现原理ConcurrentBag的高性能来源于线程本地存储 工作窃取的设计每个线程拥有一个私有小袋bag通常是链表或数组线程Add/Take时优先操作自己的私有袋几乎无锁当自己袋子为空时会去“偷”其他线程的袋子work-stealing这种设计导致同一个线程插入的元素很可能被同一个线程先取出局部性好但跨线程看完全无序而且可能出现同一个元素被同一个线程先取后放的情况轻量级锁仅在跨线程窃取元素时加锁核心路径同线程存取无锁性能远超全局锁的ListT。工作窃取工作窃取工作窃取线程A本地队列A: 1, 3, 5线程B本地队列B: 2, 4线程C本地队列C: 6全局队列核心 API核心构造函数ConcurrentBagT(): 创建空的线程安全集合ConcurrentBagT(IEnumerableT): 用指定集合初始化ConcurrentBagT核心方法 / 属性Add(T item): 向集合添加元素线程安全无返回值TryTake(out T result): 尝试从集合移除并返回任意元素成功返回true集合为空返回falseCount: 获取集合中元素的数量线程安全但值为瞬时快照IsEmpty: 判断集合是否为空线程安全瞬时快照GetEnumerator(): 返回遍历集合的枚举器遍历的是瞬时快照不保证后续元素不变常用操作varbagnewConcurrentBagstring();// 插入极快bag.Add(任务A);bag.Add(任务B);// 尝试取出非阻塞if(bag.TryTake(outvaritem)){Console.WriteLine($取出:{item});}// 尝试偷取TryPeek 不存在if(bag.TryTake(outvarstolen)){/* 处理 */}// 计数注意有一定开销intcountbag.Count;// 清空不常用bag.Clear();// 检查是否为空boolisEmptybag.IsEmpty;用法示例多线程添加与消费usingSystem;usingSystem.Collections.Concurrent;usingSystem.Threading.Tasks;classConcurrentBagBasicDemo{staticvoidMain(){// 创建线程安全的ConcurrentBagvarbagnewConcurrentBagint();// 1. 多线程添加元素4个线程每个添加5个元素Parallel.For(0,4,threadId{for(inti1;i5;i){intvaluethreadId*100i;bag.Add(value);Console.WriteLine($线程{threadId}添加{value});}});Console.WriteLine($\n集合总元素数{bag.Count}\n);// 2. 多线程消费元素直到集合为空Parallel.For(0,2,threadId{while(!bag.IsEmpty){if(bag.TryTake(outintvalue)){Console.WriteLine($线程{threadId}取出{value});}// 避免空循环占用CPUTask.Delay(10).Wait();}});Console.WriteLine($\n最终集合是否为空{bag.IsEmpty});}}输出结果线程0添加 1 线程1添加 101 线程0添加 2 线程2添加 201 ...添加顺序无序 集合总元素数20 线程0取出 2 线程1取出 101 线程0取出 1 线程1取出 201 ...取出顺序≠添加顺序且优先取当前线程添加的元素 最终集合是否为空True核心现象添加和取出的顺序完全无序符合ConcurrentBagT“无序集合” 的特性同一线程优先取出自己添加的元素TLS优化的体现。并行处理大量独立小文件varfilesDirectory.GetFiles(big_folder,*.txt);varbagnewConcurrentBagstring(files);Parallel.ForEach(bag,newParallelOptions{MaxDegreeOfParallelismEnvironment.ProcessorCount},file{ProcessFile(file);});对象池实现publicclassObjectPoolT{privatereadonlyConcurrentBagT_objects;privatereadonlyFuncT_objectGenerator;publicObjectPool(FuncTobjectGenerator){_objectsnewConcurrentBagT();_objectGeneratorobjectGenerator;}publicTGet(){return_objects.TryTake(outTitem)?item:_objectGenerator();}publicvoidReturn(Titem){_objects.Add(item);}}// 使用示例varpoolnewObjectPoolStringBuilder(()newStringBuilder());varsbpool.Get();try{sb.Append(Hello);Console.WriteLine(sb.ToString());}finally{pool.Return(sb);}关键特性与适用场景核心特性顺序性: 无序Add顺序≠遍历 /Take顺序线程安全: 所有操作线程安全无需手动加锁性能: 同线程存取极高无锁跨线程窃取中轻量级锁空值支持: 允许添加null若T为引用类型遍历特性: 遍历的是 “瞬时快照”遍历过程中集合可修改不抛出异常容量: 无固定容量限制动态扩容最佳适用场景线程自产自销线程池线程添加元素后自己快速取出处理如线程本地缓存无序批量处理多线程收集数据无需保证顺序如日志收集、临时数据存储低锁竞争场景大多数操作由同一线程完成跨线程操作少。对象池实现重用对象减少分配并行计算中间结果收集生产者即消费者模式不适用场景需要有序存取如FIFO用ConcurrentQueueT、LIFO用ConcurrentStackT高跨线程窃取多线程频繁添加且其他线程频繁取走此时锁竞争多性能低于ConcurrentQueueT索引访问ConcurrentBagT无索引如bag[0]需索引访问用ConcurrentDictionaryTKey, TValue或手动封装。最佳实践优先用于生产者-消费者同线程场景// 同一线程添加和取出varthreadLocalBagnewConcurrentBagWorkItem();voidProcess(){threadLocalBag.Add(CreateWork());if(threadLocalBag.TryTake(outvarwork)){Execute(work);}}避免用于生产者-消费者分离场景// 生产者消费者分离varsharedBagnewConcurrentBagData();// 生产者线程Task.Run(()sharedBag.Add(produce()));// 消费者线程Task.Run((){if(sharedBag.TryTake(outvardata)){consume(data);}});总结ConcurrentBagT是.NET并发集合中的特殊工具✅ 在生产者即消费者场景中性能卓越✅ 内置工作窃取机制✅ 无锁实现减少竞争✅ 线程本地存储优化最佳适用场景线程处理自己生成的任务对象池实现并行计算的结果收集工作窃取模式的任务分发