C#中神器类BlockingCollection的实现详解

C#中神器类BlockingCollection的实现详解

什么是BlockingCollection

BlockingCollection 是 C# 中一个非常有用的线程安全的集合类,用于在多线程并发环境下进行数据的读取、写入和处理。它的用途非常广泛,比如在生产者-消费者模型中,用于协调生产者和消费者之间的数据传输,以及在大数据处理中,用于使用多个线程处理大规模的数据并发。

BlockingCollection的实现原理

BlockingCollection 是基于 ConcurrentQueue 实现的,底层用到了 Monitor.Wait()Monitor.Pulse() 进行线程同步。在集合为空时,调用 Take() 方法的线程会被阻塞,直到队列中有可用的数据;在队列满时,调用 Add() 方法的线程会被阻塞,直到队列有空闲的空间。

BlockingCollection的基本用法

创建BlockingCollection

在使用 BlockingCollection 之前,首先需要进行实例化:

var collection = new BlockingCollection<T>();

其中,T 为要存储的数据类型。

添加数据

可以使用 Add() 方法向 BlockingCollection 中添加数据:

collection.Add(data);

如果队列已满,Add() 方法会阻塞当前线程,直到队列有可用的空间。

取出数据

可以使用 Take() 方法从 BlockingCollection 中取出数据:

var data = collection.Take();

如果队列为空,Take() 方法会阻塞当前线程,直到队列中有可用的数据。

遍历数据

可以使用 foreach 循环遍历 BlockingCollection 中的数据:

foreach(var data in collection)
{
    // 处理数据
}

完成添加

在生产者向队列中添加完数据后,需要调用 CompleteAdding() 告知消费者已经完成添加操作:

collection.CompleteAdding();

判断是否有数据

可以使用 IsCompleted()Count 属性判断集合是否已经完成添加,以及队列中当前的元素个数:

if(collection.IsCompleted && collection.Count == 0)
{
    // 队列已经处理完毕
}

BlockingCollection的高级用法

设置队列的最大容量

可以在实例化 BlockingCollection 时指定队列的最大容量:

var collection = new BlockingCollection<T>(capacity);

设置超时等待

可以使用 Take()Add() 方法的带有超时参数的方法,来指定线程的等待时间:

var data = collection.Take(timeout);
collection.Add(data, timeout);

设置取消标志

可以使用 CancellationToken 对象来取消队列的操作,例如:

var cts = new CancellationTokenSource();

Task.Run(() =>
{
    while(!collection.IsAddingCompleted)
    {
        var data = collection.Take(cts.Token);
        // 处理数据
    }
});

// 取消操作
cts.Cancel();

示例1:生产者消费者模型

以下示例展示了 BlockingCollection 在生产者-消费者模型中的基本用法:

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

class Program
{
    static void Main(string[] args)
    {
        var collection = new BlockingCollection<int>(5);

        // 生产者
        Task.Run(() =>
        {
            for (int i = 0; i < 10; i++)
            {
                collection.Add(i);
                Console.WriteLine($"生产者产生了数据{i},当前队列中元素个数为{collection.Count}");
            }
            // 完成添加
            collection.CompleteAdding();
        });

        // 消费者
        Task.Run(() =>
        {
            while (!collection.IsCompleted)
            {
                var data = collection.Take();
                Console.WriteLine($"消费者消费了数据{data},当前队列中元素个数为{collection.Count}");
                // 模拟耗时操作
                Thread.Sleep(1000);
            }
        });

        Console.Read();
    }
}

在上面的示例中,生产者不停地向队列中添加数据,每当添加完一个数字时就会打印出当前队列中元素个数;消费者不停地从队列中取出数据,并且每当取出一个数字时会打印出当前队列中元素个数。

当所有的数据都被生产者添加进队列中后,消费者就会停止取出数据,而由于生产者调用了 CompleteAdding() 方法,所以消费者不会再等待添加操作,从而退出循环。

示例2:并发任务处理

以下示例展示了如何使用 BlockingCollection 实现并发任务处理:

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

class Program
{
    static void Main(string[] args)
    {
        var collection = new BlockingCollection<int>();

        var sw = new Stopwatch();
        sw.Start();
        // 并发执行10个任务
        for (int i = 0; i < 10; i++)
        {
            var task = Task.Run(() =>
            {
                for (int j = 0; j < 1000000; j++)
                {
                    collection.Add(j);
                }
            });
        }

        Task.Run(() =>
        {
            while (!collection.IsCompleted)
            {
                var data = collection.Take();
                // 处理数据
            }
        }).Wait();

        sw.Stop();
        Console.WriteLine($"处理1亿条数据所需时间:{sw.ElapsedMilliseconds} ms");

        Console.Read();
    }
}

在上面的示例中,我们启动了10个并发任务,每个任务都向 BlockingCollection 中添加了100万条数字数据。最后,我们启动一个消费者任务,从队列中取出所有的数据,进行处理。运行结果表明,在多线程并发情况下,使用 BlockingCollection 去协调和同步数据的读取和写入,可以极大地提升程序的运行效率。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C#中神器类BlockingCollection的实现详解 - Python技术站

(0)
上一篇 2023年5月31日
下一篇 2023年5月31日

相关文章

  • Unity 修改FBX模型动画的操作

    下面是关于“Unity 修改FBX模型动画的操作”的完整攻略,具体内容如下: 1. 导入FBX模型和动画 在Unity的Assets面板中右键点击空白区域,选择Import New Asset,将FBX模型和动画导入到项目中。导入时要确保勾选了Import Animations选项,以便将动画一起导入进来。 2. 创建动画控制器(Controller) 选中…

    C# 2023年6月3日
    00
  • C#如何用ThoughtWorks生成二维码

    生成二维码可以使用ThoughtWorks开源的ZXing库。以下是使用C#利用ThoughtWorks生成二维码的完整攻略: 步骤一:引入依赖 使用ZXing生成二维码需要引入ThoughtWorks.QRCode的Nuget包。在Visual Studio中,可以通过在“解决方案资源管理器”中右键点击项目,选择“管理NuGet程序包”来搜索并安装Thou…

    C# 2023年6月6日
    00
  • C#集合本质之队列的用法详解

    C#集合本质之队列的用法详解 什么是队列 队列是计算机科学中一种抽象数据类型,表示先进先出 (FIFO) 的线性数据结构。在队列中,元素从后端(也称为队尾)入队,从前端(也称为队首)出队。队列常用于存储按顺序排列的数据,如等待处理的请求和待打印的文档等。 C#中的队列 C#中的队列是由System.Collections命名空间下的Queue类实现的,它是一…

    C# 2023年6月7日
    00
  • C# memcache 使用介绍

    C#memcache使用介绍 Memcache是一种基于内存的缓存服务,通过存储在内存中的数据来提升Web应用程序的性能。在C#中,可以通过使用开源的MongoDB.Driver.Net软件包来进行Memcache的使用。 1. 安装MongoDB.Driver.Net 在C#中使用Memcache需要先安装MongoDB.Driver.Net软件包,可以通…

    C# 2023年5月15日
    00
  • ASP.NET Core 3.0使用gRPC的具体方法

    ASP.NET Core 3.0使用gRPC的具体方法 简介 gRPC 是由 Google 开发的一种高性能、开源的远程过程调用(RPC)框架。它使用 Protocol Buffers 作为数据交换格式,可以在多种语言之间进行通信。在 .NET Core 3.0 中,我们可以通过 gRPC 快速建立一个高效的微服务。 快速入门 创建 gRPC 服务 我们可以…

    C# 2023年6月3日
    00
  • C#框架winform实现简单点餐系统

    下面是详细讲解“C#框架winform实现简单点餐系统”的完整攻略。 1. 准备工作 在正式开始开发点餐系统之前,需要准备好相关的工具和资源,以下是准备工作的具体步骤: 1.1 安装Visual Studio Visual Studio是Windows平台下的一款集成开发环境,它支持多种编程语言,其中包括C#。因此,我们需要安装Visual Studio来进…

    C# 2023年6月3日
    00
  • Asp.Net中的字符串和HTML十进制编码转换实现代码

    下面我将详细讲解如何在 Asp.Net 中实现字符串和 HTML 十进制编码的转换。 什么是字符串和 HTML 十进制编码? 在 Asp.Net 中,字符串就是一串字符(可以包含字母、数字、符号等),我们可以将其在程序中进行处理、传递和展示。而 HTML 十进制编码则是将字符按照其在 ASCII 表中对应的值进行转化,用十进制数字表示。 用 Asp.Net …

    C# 2023年5月31日
    00
  • asp.net 冒泡算法的理解

    接下来我将详细讲解“ASP.NET 冒泡算法的理解”的攻略。 冒泡算法 冒泡算法是一种排序算法,它通过重复地交换相邻的两个元素,从而将未排序的元素逐个地移动到已排序的位置。冒泡排序的基本思路是将待排序的元素序列两两比较,如果顺序不对则交换,一趟排序下来保证最大(或最小)元素出现在序列的末尾。然后对剩下的元素进行相同的操作,直到整个序列有序。这个过程像气泡冒到…

    C# 2023年6月3日
    00
合作推广
合作推广
分享本页
返回顶部