最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#.NET?ConcurrentBag<T>?設(shè)計(jì)原理與使用場(chǎng)景

 更新時(shí)間:2026年01月12日 09:32:43   作者:唐青楓  
ConcurrentBag<T>?是System.Collections.Concurrent?命名空間下的線程安全的無(wú)序集合,本文就來(lái)詳細(xì)的介紹一下C#.NET?ConcurrentBag<T>?原理與使用,感興趣的可以了解一下

簡(jiǎn)介

ConcurrentBag<T>System.Collections.Concurrent 命名空間下的線程安全的無(wú)序集合,專(zhuān)為 “多線程同時(shí)添加 / 移除元素” 設(shè)計(jì),核心特點(diǎn)是基于線程局部存儲(chǔ)(TLS)優(yōu)化,在 “同一線程頻繁添加和移除元素” 的場(chǎng)景下性能最優(yōu),是 .NET 中處理無(wú)序線程安全集合的核心工具。

核心定位與價(jià)值

在多線程場(chǎng)景中,普通的 List<T> 非線程安全(多線程操作會(huì)拋出異?;驍?shù)據(jù)損壞),而 lock 包裹的 List<T> 存在鎖競(jìng)爭(zhēng)問(wèn)題(性能低)。ConcurrentBag<T> 的核心價(jià)值:

  • 無(wú)鎖核心路徑:通過(guò)線程局部存儲(chǔ)(TLS)讓每個(gè)線程優(yōu)先操作自己的私有數(shù)據(jù)段,減少跨線程鎖競(jìng)爭(zhēng);
  • 無(wú)序存儲(chǔ):不保證元素的順序(插入順序≠遍歷順序),犧牲順序換取性能;
  • 線程安全:所有操作(Add/TryTake 等)均線程安全,無(wú)需手動(dòng)加鎖;
  • 適配特定場(chǎng)景:尤其適合 “生產(chǎn)者和消費(fèi)者為同一線程” 的場(chǎng)景(如線程池線程自產(chǎn)自銷(xiāo))。

核心特點(diǎn)

特性ConcurrentBagConcurrentQueueConcurrentStack典型使用場(chǎng)景
順序保證無(wú)序(完全不保證)FIFOLIFO不關(guān)心順序的場(chǎng)景
線程安全多線程并發(fā)
元素重復(fù)取出風(fēng)險(xiǎn)可能(同一個(gè)線程可能先取后放)不可能不可能允許“偷取”工作
內(nèi)存使用較低(分段 + 線程本地袋)中等中等大量小對(duì)象
支持 Peek不支持支持支持
典型模式工作竊?。╳ork-stealing)生產(chǎn)者-消費(fèi)者后進(jìn)先出任務(wù)棧并行任務(wù)池、負(fù)載均衡

內(nèi)部實(shí)現(xiàn)原理

ConcurrentBag 的高性能來(lái)源于線程本地存儲(chǔ) + 工作竊取的設(shè)計(jì):

  • 每個(gè)線程擁有一個(gè)私有小袋(bag)(通常是鏈表或數(shù)組)
  • 線程 Add/Take 時(shí)優(yōu)先操作自己的私有袋(幾乎無(wú)鎖)
  • 當(dāng)自己袋子為空時(shí),會(huì)去 “偷” 其他線程的袋子( work-stealing

這種設(shè)計(jì)導(dǎo)致:

  • 同一個(gè)線程插入的元素,很可能被同一個(gè)線程先取出(局部性好)
  • 但跨線程看,完全無(wú)序,而且可能出現(xiàn)同一個(gè)元素被同一個(gè)線程先取后放的情況

輕量級(jí)鎖:僅在跨線程竊取元素時(shí)加鎖,核心路徑(同線程存取)無(wú)鎖,性能遠(yuǎn)超全局鎖的 List<T>

graph TD
    A[線程A] --> A_Queue[本地隊(duì)列A: 1, 3, 5]
    B[線程B] --> B_Queue[本地隊(duì)列B: 2, 4]
    C[線程C] --> C_Queue[本地隊(duì)列C: 6]
    
    D[全局隊(duì)列] --> |工作竊取| A_Queue
    D --> |工作竊取| B_Queue
    D --> |工作竊取| C_Queue

核心 API

核心構(gòu)造函數(shù)

  • ConcurrentBag<T>(): 創(chuàng)建空的線程安全集合
  • ConcurrentBag<T>(IEnumerable<T>): 用指定集合初始化ConcurrentBag<T>

核心方法 / 屬性

  • Add(T item): 向集合添加元素(線程安全),無(wú)返回值
  • TryTake(out T result): 嘗試從集合移除并返回任意元素:成功返回true,集合為空返回 false
  • Count: 獲取集合中元素的數(shù)量(線程安全,但值為瞬時(shí)快照)
  • IsEmpty: 判斷集合是否為空(線程安全,瞬時(shí)快照)
  • GetEnumerator(): 返回遍歷集合的枚舉器(遍歷的是瞬時(shí)快照,不保證后續(xù)元素不變)

常用操作

var bag = new ConcurrentBag<string>();

// 插入(極快)
bag.Add("任務(wù)A");
bag.Add("任務(wù)B");

// 嘗試取出(非阻塞)
if (bag.TryTake(out var item))
{
    Console.WriteLine($"取出: {item}");
}

// 嘗試偷取(TryPeek 不存在?。?
if (bag.TryTake(out var stolen)) { /* 處理 */ }

// 計(jì)數(shù)(注意:有一定開(kāi)銷(xiāo))
int count = bag.Count;

// 清空(不常用)
bag.Clear();

// 檢查是否為空
bool isEmpty = bag.IsEmpty;

用法示例

多線程添加與消費(fèi)

using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;

class ConcurrentBagBasicDemo
{
    static void Main()
    {
        // 創(chuàng)建線程安全的ConcurrentBag
        var bag = new ConcurrentBag<int>();

        // 1. 多線程添加元素(4個(gè)線程,每個(gè)添加5個(gè)元素)
        Parallel.For(0, 4, threadId =>
        {
            for (int i = 1; i <= 5; i++)
            {
                int value = threadId * 100 + i;
                bag.Add(value);
                Console.WriteLine($"線程{threadId}:添加 {value}");
            }
        });

        Console.WriteLine($"\n集合總元素?cái)?shù):{bag.Count}\n");

        // 2. 多線程消費(fèi)元素(直到集合為空)
        Parallel.For(0, 2, threadId =>
        {
            while (!bag.IsEmpty)
            {
                if (bag.TryTake(out int value))
                {
                    Console.WriteLine($"線程{threadId}:取出 {value}");
                }
                // 避免空循環(huán)占用CPU
                Task.Delay(10).Wait();
            }
        });

        Console.WriteLine($"\n最終集合是否為空:{bag.IsEmpty}");
    }
}

輸出結(jié)果

線程0:添加 1
線程1:添加 101
線程0:添加 2
線程2:添加 201
...(添加順序無(wú)序)
集合總元素?cái)?shù):20

線程0:取出 2
線程1:取出 101
線程0:取出 1
線程1:取出 201
...(取出順序≠添加順序,且優(yōu)先取當(dāng)前線程添加的元素)
最終集合是否為空:True

核心現(xiàn)象:

  • 添加和取出的順序完全無(wú)序,符合 ConcurrentBag<T> “無(wú)序集合” 的特性;
  • 同一線程優(yōu)先取出自己添加的元素(TLS 優(yōu)化的體現(xiàn))。

并行處理大量獨(dú)立小文件

var files = Directory.GetFiles("big_folder", "*.txt");
var bag = new ConcurrentBag<string>(files);

Parallel.ForEach(bag, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount },
    file =>
    {
        ProcessFile(file);
    });

對(duì)象池實(shí)現(xiàn)

public class ObjectPool<T>
{
    private readonly ConcurrentBag<T> _objects;
    private readonly Func<T> _objectGenerator;

    public ObjectPool(Func<T> objectGenerator)
    {
        _objects = new ConcurrentBag<T>();
        _objectGenerator = objectGenerator;
    }

    public T Get()
    {
        return _objects.TryTake(out T item) ? item : _objectGenerator();
    }

    public void Return(T item)
    {
        _objects.Add(item);
    }
}

// 使用示例
var pool = new ObjectPool<StringBuilder>(() => new StringBuilder());
var sb = pool.Get();
try
{
    sb.Append("Hello");
    Console.WriteLine(sb.ToString());
}
finally
{
    pool.Return(sb);
}

關(guān)鍵特性與適用場(chǎng)景

核心特性

  • 順序性: 無(wú)序(Add 順序≠遍歷 / Take 順序)
  • 線程安全: 所有操作線程安全,無(wú)需手動(dòng)加鎖
  • 性能: 同線程存?。簶O高(無(wú)鎖);跨線程竊?。褐校ㄝp量級(jí)鎖)
  • 空值支持: 允許添加 null(若T為引用類(lèi)型)
  • 遍歷特性: 遍歷的是 “瞬時(shí)快照”,遍歷過(guò)程中集合可修改,不拋出異常
  • 容量: 無(wú)固定容量限制,動(dòng)態(tài)擴(kuò)容

最佳適用場(chǎng)景

  • 線程自產(chǎn)自銷(xiāo):線程池線程添加元素后,自己快速取出處理(如線程本地緩存);
  • 無(wú)序批量處理:多線程收集數(shù)據(jù),無(wú)需保證順序(如日志收集、臨時(shí)數(shù)據(jù)存儲(chǔ));
  • 低鎖競(jìng)爭(zhēng)場(chǎng)景:大多數(shù)操作由同一線程完成,跨線程操作少。
  • 對(duì)象池實(shí)現(xiàn):重用對(duì)象減少分配
  • 并行計(jì)算中間結(jié)果收集
  • 生產(chǎn)者即消費(fèi)者模式

不適用場(chǎng)景

  • 需要有序存?。喝?FIFO(用 ConcurrentQueue<T> )、LIFO(用ConcurrentStack<T>);
  • 高跨線程竊?。憾嗑€程頻繁添加,且其他線程頻繁取走(此時(shí)鎖競(jìng)爭(zhēng)多,性能低于ConcurrentQueue<T> );
  • 索引訪問(wèn):ConcurrentBag<T> 無(wú)索引(如 bag[0] ),需索引訪問(wèn)用ConcurrentDictionary<TKey, TValue> 或手動(dòng)封裝。

最佳實(shí)踐

優(yōu)先用于生產(chǎn)者-消費(fèi)者同線程場(chǎng)景

   // 同一線程添加和取出
   var threadLocalBag = new ConcurrentBag<WorkItem>();
   
   void Process()
   {
       threadLocalBag.Add(CreateWork());
       if (threadLocalBag.TryTake(out var work))
       {
           Execute(work);
       }
   }

避免用于生產(chǎn)者-消費(fèi)者分離場(chǎng)景

   // 生產(chǎn)者消費(fèi)者分離
   var sharedBag = new ConcurrentBag<Data>();
   
   // 生產(chǎn)者線程
   Task.Run(() => sharedBag.Add(produce()));
   
   // 消費(fèi)者線程
   Task.Run(() => 
   {
       if (sharedBag.TryTake(out var data))
       {
           consume(data);
       }
   });

總結(jié)

ConcurrentBag<T>.NET 并發(fā)集合中的特殊工具:

  • ? 在生產(chǎn)者即消費(fèi)者場(chǎng)景中性能卓越
  • ? 內(nèi)置工作竊取機(jī)制
  • ? 無(wú)鎖實(shí)現(xiàn)減少競(jìng)爭(zhēng)
  • ? 線程本地存儲(chǔ)優(yōu)化

最佳適用場(chǎng)景:

  • 線程處理自己生成的任務(wù)
  • 對(duì)象池實(shí)現(xiàn)
  • 并行計(jì)算的結(jié)果收集
  • 工作竊取模式的任務(wù)分發(fā)

到此這篇關(guān)于C#.NET ConcurrentBag<T>設(shè)計(jì)原理與使用場(chǎng)景的文章就介紹到這了,更多相關(guān)C#.NET ConcurrentBag<T>使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C#如何使用XmlDocument訪問(wèn)XML文件

    C#如何使用XmlDocument訪問(wèn)XML文件

    本文介紹了XML文件的特點(diǎn)、用途、格式、示例、解析和處理方式,以及在C#中使用XmlDocument類(lèi)進(jìn)行增刪改查操作的方法,XML文件是一種靈活的數(shù)據(jù)描述和存儲(chǔ)方式,適用于各種應(yīng)用場(chǎng)景,在C#中,通過(guò)XmlDocument類(lèi)可以方便地對(duì)XML文件進(jìn)行操作
    2024-12-12
  • 基于C#實(shí)現(xiàn)網(wǎng)絡(luò)爬蟲(chóng) C#抓取網(wǎng)頁(yè)Html源碼

    基于C#實(shí)現(xiàn)網(wǎng)絡(luò)爬蟲(chóng) C#抓取網(wǎng)頁(yè)Html源碼

    這篇文章主要為大家詳細(xì)介紹了基于C#實(shí)現(xiàn)網(wǎng)絡(luò)爬蟲(chóng)的相關(guān)資料,即C#抓取網(wǎng)頁(yè)Html源碼,感興趣的小伙伴們可以參考一下
    2016-03-03
  • Unity的IFilterBuildAssemblies實(shí)用案例深入解析

    Unity的IFilterBuildAssemblies實(shí)用案例深入解析

    這篇文章主要為大家介紹了Unity的IFilterBuildAssemblies實(shí)用案例深入解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • C#中DataGridView常用操作實(shí)例小結(jié)

    C#中DataGridView常用操作實(shí)例小結(jié)

    這篇文章主要介紹了C#中DataGridView常用操作,以實(shí)例形式總結(jié)了DataGridView綁定下拉列表、設(shè)置默認(rèn)值、判斷復(fù)選框是否選中等技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-09-09
  • C#編程實(shí)現(xiàn)四舍五入、向上及下取整的方法

    C#編程實(shí)現(xiàn)四舍五入、向上及下取整的方法

    這篇文章主要介紹了C#編程實(shí)現(xiàn)四舍五入、向上及下取整的方法,涉及C#數(shù)學(xué)運(yùn)算的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-11-11
  • Unity利用XML制作一個(gè)簡(jiǎn)易的登錄系統(tǒng)

    Unity利用XML制作一個(gè)簡(jiǎn)易的登錄系統(tǒng)

    這篇文章主要介紹了如何在Unity中利用XML文件制作一個(gè)簡(jiǎn)易的登錄系統(tǒng),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-03-03
  • C#實(shí)現(xiàn)微信紅包功能

    C#實(shí)現(xiàn)微信紅包功能

    這篇文章主要介紹了C#實(shí)現(xiàn)微信紅包功能,使用正態(tài)分布計(jì)算紅包金額,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • C#實(shí)現(xiàn)希爾排序算法的實(shí)踐

    C#實(shí)現(xiàn)希爾排序算法的實(shí)踐

    希爾排序算法是基于插入排序改進(jìn)的一種排序方法,通過(guò)分組和遞減增量的策略來(lái)提高排序效率,學(xué)習(xí)希爾排序可以幫助理解排序算法原理,拓寬算法思維,并解決實(shí)際問(wèn)題,感興趣的可以了解一下
    2024-10-10
  • C#?MemoryStream的具體使用

    C#?MemoryStream的具體使用

    MemoryStream是.NET中用于內(nèi)存數(shù)據(jù)讀寫(xiě)的流類(lèi),速度快且靈活,適用于臨時(shí)緩存、二進(jìn)制處理等場(chǎng)景,下面就來(lái)詳細(xì)的介紹一下MemoryStream的使用,感興趣的可以了解一下
    2025-07-07
  • c# 遞歸訪問(wèn)文件夾(刪掉歌詞文件)

    c# 遞歸訪問(wèn)文件夾(刪掉歌詞文件)

    今天想把我的音樂(lè)里面500首的mp3都拷到手機(jī)里,不過(guò)這些mp3都有很多層目錄,而且每首歌曲都還有歌詞文件,我只想留下mp3,歌詞文件都刪掉,就寫(xiě)了個(gè)小程序跑一下,比手動(dòng)刪快多了
    2012-06-06

最新評(píng)論

凤翔县| 蕉岭县| 精河县| 公主岭市| 若羌县| 海城市| 长海县| 天镇县| 新兴县| 嘉禾县| 陇南市| 南投县| 石家庄市| 综艺| 吉安县| 葵青区| 大同县| 青龙| 高青县| 南江县| 措勤县| 安多县| 金湖县| 白河县| 长海县| 梅河口市| 平山县| 房产| 麦盖提县| 桃园市| 牟定县| 通海县| 兰考县| 丹东市| 龙州县| 潜山县| 乐亭县| 宣汉县| 七台河市| 塔城市| 通河县|