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日

相关文章

  • 教你创建一个带诊断工具的.NET镜像

    教你创建一个带诊断工具的.NET镜像 在.NET应用程序中,诊断工具是一项非常重要的任务,它可以帮助您跟踪应用程序的运行情况并诊断问题。在本攻略,我们将详细讲解如何创建一个带诊断工具的.NET镜像,并提供两个示例说明。 步骤一:创建Dockerfile 要创建一个带诊断工具的.NET镜像,您需要创建一个Dockerfile。以下是Dockerfile的示例代…

    C# 2023年5月17日
    00
  • .net core中Grpc使用报错:The remote certificate is invalid according to the validation procedure.

    因为Grpc采用HTTP/2作为通信协议,默认采用LTS/SSL加密方式传输,比如使用.net core启动一个服务端(被调用方)时:   public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWe…

    C# 2023年4月19日
    00
  • 浅析C# 使用Process调用外部程序中所遇到的参数问题

    浅析C#使用Process调用外部程序中所遇到的参数问题 介绍 在使用C#中的Process类调用外部程序时,我们常常会遇到参数问题,例如,我们想要执行ping www.google.com这条命令,但是在C#程序中调用时,却无法成功执行。本篇文章将详细讲解在使用C#中的Process类调用外部程序时所遇到的参数问题及其解决方案。 参数问题 当我们使用Pro…

    C# 2023年5月15日
    00
  • .NET6使用ImageSharp实现给图片添加水印

    以下是关于“.NET6使用ImageSharp实现给图片添加水印”的完整攻略: 1. 什么是ImageSharp? ImageSharp是一个.NET的图像处理库,它提供了一种简单的方式来处理图像。ImageSharp支持各种图像格式,例如JPEG、PNG、BMP、GIF等,并提供了一些有用的功能,例如调整大小、裁剪、旋转、添加水印等。 2. 安装Image…

    C# 2023年5月12日
    00
  • C#编程和Visual Studio使用技巧(上)

    C#编程和VisualStudio使用技巧(上)完整攻略 1. 简介 本文主要讲解C#编程和Visual Studio的使用技巧。C#是一种现代化的、强类型的面向对象编程语言,常用于开发Windows应用程序、Web应用程序和游戏等。Visual Studio则是开发C#应用程序的主要工具之一,提供了强大的集成开发环境(IDE)以及各种调试、测试和部署工具等…

    C# 2023年5月14日
    00
  • ASP.NET Core Web资源打包与压缩技术介绍

    在ASP.NET Core中,可以使用Web资源打包和压缩技术来提高Web应用程序的性能和加载速度。本文将介绍ASP.NET Core Web资源打包和压缩技术的完整攻略。 步骤 步骤1:安装Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation包 首先,需要安装Microsoft.AspNetCore.Mvc.R…

    C# 2023年5月17日
    00
  • 详解如何通过C#/VB.NET调整PDF文档页边距

    请参考以下完整攻略: 1. 安装依赖库 要使用C#/VB.NET调整PDF文档页边距,我们需要使用一个PDF库来操作PDF文档。这里我们使用iTextSharp库来进行操作。在Visual Studio中打开项目,右键单击项目,然后选择“管理NuGet包”。在NuGet包管理器中搜索“iTextSharp”,然后离线安装。 2. 加载PDF文档 使用iTex…

    C# 2023年6月6日
    00
  • c# 死锁和活锁的发生及避免

    C# 死锁和活锁的发生及避免攻略 什么是死锁和活锁 死锁和活锁都是多线程并发编程中经常遇到的问题。 死锁 死锁指的是两个或更多的线程被永久地阻塞,无法继续执行,因为每个线程都在等待其他线程释放资源。简单来说,就是线程之间互相占用对方需要的资源,并不释放,而导致程序无限等待下去。 活锁 活锁指的是线程虽然没有被阻塞,但是他们却无法继续前进,因为它们总是在响应其…

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