浅谈C#之ConcurrentQueue

一、基本介绍

ConcurrentQueue<T> 是一个线程安全的队列,它允许多个线程同时对队列进行操作而不会相互干扰。它是 System.Collections.Concurrent 命名空间下的一个类,提供了基本的队列操作,如 Enqueue(入队)、TryDequeue(尝试出队)、TryPeek(尝试查看队首元素)等,并且是线程安全的。

二、关键特性

线程安全:不需要额外的同步机制,就可以在多线程环境中安全地使用。

无锁:内部使用原子操作来保证线程安全,通常比使用锁有更好的性能。

阻塞操作 :虽然 ConcurrentQueue<T> 本身不提供阻塞操作,但可以与其他同步原语(如 SemaphoreSlimCancellationToken)结合使用来实现阻塞行为

三、简单示例

cs 复制代码
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static void Main()
    {
        ConcurrentQueue<int> queue = new ConcurrentQueue<int>();
        CancellationTokenSource cts = new CancellationTokenSource();

        // 生产者线程
        Task producer = Task.Run(() =>
        {
            for (int i = 0; i < 10; i++)
            {
                queue.Enqueue(i);
                Console.WriteLine($"Produced: {i}");
                Thread.Sleep(100); // 模拟工作
            }
        }, cts.Token);

        // 消费者线程
        Task consumer = Task.Run(() =>
        {
            while (!cts.Token.IsCancellationRequested)
            {
                if (queue.TryDequeue(out int item))
                {
                    Console.WriteLine($"Consumed: {item}");
                }
                else
                {
                    Thread.Yield(); // 让出 CPU 时间片
                }
            }
        }, cts.Token);

        // 等待一段时间,然后取消任务
        Thread.Sleep(1500);
        cts.Cancel();

        Task.WaitAll(producer, consumer);
    }
}

四、完整示例

1.与 BlockingCollection<T> 结合使用

BlockingCollection<T> 是一个线程安全的集合,提供了数据结构和同步原语的组合,可以与 ConcurrentQueue<T> 结合使用来实现生产者-消费者模式。

cs 复制代码
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static void Main()
    {
        BlockingCollection<int> blockingCollection = new BlockingCollection<int>(new ConcurrentQueue<int>(), 10);

        Task producer = Task.Run(() =>
        {
            for (int i = 0; i < 20; i++)
            {
                blockingCollection.Add(i);
                Console.WriteLine($"Produced: {i}");
                Thread.Sleep(100);
            }
            blockingCollection.CompleteAdding();
        });

        Task consumer = Task.Run(() =>
        {
            foreach (var item in blockingCollection.GetConsumingEnumerable())
            {
                Console.WriteLine($"Consumed: {item}");
                Thread.Sleep(150);
            }
        });

        Task.WaitAll(producer, consumer);
    }
}

2. 使用 CancellationToken 实现优雅的取消

ConcurrentQueue<T> 可以与 CancellationToken 结合使用,以实现任务的优雅取消。

cs 复制代码
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static void Main()
    {
        ConcurrentQueue<int> queue = new ConcurrentQueue<int>();
        CancellationTokenSource cts = new CancellationTokenSource();

        Task producer = Task.Run(() =>
        {
            for (int i = 0; i < 20; i++)
            {
                if (cts.Token.IsCancellationRequested)
                {
                    Console.WriteLine("Cancellation requested");
                    return;
                }
                queue.Enqueue(i);
                Console.WriteLine($"Produced: {i}");
                Thread.Sleep(100);
            }
        }, cts.Token);

        Task consumer = Task.Run(() =>
        {
            while (!cts.Token.IsCancellationRequested)
            {
                if (queue.TryDequeue(out int item))
                {
                    Console.WriteLine($"Consumed: {item}");
                }
                else
                {
                    Thread.Yield();
                }
            }
        }, cts.Token);

        Thread.Sleep(1500);
        cts.Cancel();

        Task.WaitAll(producer, consumer);
    }
}

SemaphoreSlim 实现并发控制

SemaphoreSlim 可以与 ConcurrentQueue<T> 结合使用,以控制同时访问资源的线程数量。

cs 复制代码
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static void Main()
    {
        ConcurrentQueue<int> queue = new ConcurrentQueue<int>();
        SemaphoreSlim semaphore = new SemaphoreSlim(3);

        Task producer = Task.Run(() =>
        {
            for (int i = 0; i < 20; i++)
            {
                semaphore.Wait();
                queue.Enqueue(i);
                Console.WriteLine($"Produced: {i}");
                Thread.Sleep(100);
                semaphore.Release();
            }
        });

        Task consumer = Task.Run(() =>
        {
            while (!queue.IsEmpty)
            {
                semaphore.Wait();
                if (queue.TryDequeue(out int item))
                {
                    Console.WriteLine($"Consumed: {item}");
                    Thread.Sleep(150);
                }
                semaphore.Release();
            }
        });

        Task.WaitAll(producer, consumer);
    }
}

使用 IProducerConsumerCollection<T> 接口

ConcurrentQueue<T> 实现了 IProducerConsumerCollection<T> 接口,这使得它可以与任何需要这种接口的 API 一起使用。

cs 复制代码
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static void Main()
    {
        IProducerConsumerCollection<int> collection = new ConcurrentQueue<int>();

        Task producer = Task.Run(() =>
        {
            for (int i = 0; i < 20; i++)
            {
                collection.TryAdd(i);
                Console.WriteLine($"Produced: {i}");
                Thread.Sleep(100);
            }
        });

        Task consumer = Task.Run(() =>
        {
            while (collection.TryTake(out int item))
            {
                Console.WriteLine($"Consumed: {item}");
                Thread.Sleep(150);
            }
        });

        Task.WaitAll(producer, consumer);
    }
}
相关推荐
夏天想6 分钟前
vant4+vue3上传一个pdf文件并实现pdf的预览。使用插件pdf.js
开发语言·javascript·pdf·vant
惊鸿一博8 分钟前
c++ &&(通用引用)和&(左值引用)区别
开发语言·c++
企鹅不耐热.11 分钟前
Scala基础知识6
开发语言·后端·scala
A林玖12 分钟前
【计算机相关学习】R语言
开发语言·学习·r语言
与火星的孩子对话33 分钟前
Unity3D开发AI桌面精灵/宠物系列 【三】 语音识别 ASR 技术、语音转文本多平台 - 支持科大讯飞、百度等 C# 开发
人工智能·unity·c#·游戏引擎·语音识别·宠物
暮雨哀尘38 分钟前
微信小程序开发:开发实践
开发语言·算法·微信小程序·小程序·notepad++·性能·技术选型
冷琅辞1 小时前
Go语言的嵌入式网络
开发语言·后端·golang
response_L1 小时前
国产系统统信uos和麒麟v10在线打开word给表格赋值
java·c#·word·信创·在线编辑
Cool----代购系统API1 小时前
跨境速卖通与 API 接口数据分析
开发语言·python
User_芊芊君子1 小时前
【Java】类和对象
java·开发语言