导读:本期聚焦于小伙伴创作的《.NET中的SemaphoreSlim是什么?如何限制对资源的并发访问数量?》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《.NET中的SemaphoreSlim是什么?如何限制对资源的并发访问数量?》有用,将其分享出去将是对创作者最好的鼓励。

在.NET多线程编程中,当多个线程需要同时操作共享资源时,如果不做并发控制,很容易引发资源争抢、数据不一致或者系统负载过高的问题。SemaphoreSlim是.NET框架提供的轻量级信号量工具,专门用于控制同时访问特定资源的线程数量,适合进程内的并发场景使用。

.NET中的SemaphoreSlim是什么?如何限制对资源的并发访问数量?

SemaphoreSlim的核心概念

SemaphoreSlim本质是一个计数信号量,它维护了两个重要的数值:初始并发数量和最大并发数量。当一个线程需要访问受保护的资源时,需要先获取信号量,如果当前可用信号量数量大于0,线程就可以继续执行,同时可用信号量数量减1;如果可用信号量数量为0,线程就会被阻塞,直到有其他线程释放信号量。

和传统的Semaphore类相比,SemaphoreSlim不需要依赖操作系统的内核对象,开销更小,性能更好,但是它不支持跨进程的同步,只适合在同一个进程内的多线程场景使用。

SemaphoreSlim的常用方法

SemaphoreSlim提供了几个核心方法用于实现并发控制,常用的方法如下:

  • WaitAsync / Wait:用于获取信号量,Wait是同步方法,WaitAsync是异步方法,支持异步场景下的并发控制,调用后如果当前没有可用信号量,线程会进入等待状态。
  • Release:用于释放信号量,每调用一次,可用信号量数量加1,如果有等待的线程,会唤醒其中一个等待的线程。
  • AvailableWaitHandle:获取一个用于等待信号量的WaitHandle,不过SemaphoreSlim本身不推荐使用这个属性,因为它的设计初衷是轻量级实现。

使用SemaphoreSlim限制资源并发访问的示例

下面通过一个实际的例子来展示如何使用SemaphoreSlim限制对共享资源的并发访问数量,假设我们有一个需要限制同时最多3个线程访问的数据库查询资源。

同步场景示例

首先看同步方法的使用方式:

using System;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    // 初始化SemaphoreSlim,初始并发数为3,最大并发数也为3
    private static SemaphoreSlim _semaphore = new SemaphoreSlim(3, 3);
    // 模拟共享资源,这里用静态变量记录当前访问的线程数
    private static int _currentAccessCount = 0;

    static void Main(string[] args)
    {
        // 启动10个线程模拟并发访问
        for (int i = 0; i < 10; i++)
        {
            int threadId = i;
            Task.Run(() => AccessResource(threadId));
        }

        Console.ReadLine();
    }

    static void AccessResource(int threadId)
    {
        Console.WriteLine($"线程{threadId}等待获取资源访问权限");
        // 获取信号量,同步等待
        _semaphore.Wait();
        try
        {
            // 模拟资源访问操作
            Interlocked.Increment(ref _currentAccessCount);
            Console.WriteLine($"线程{threadId}获取到权限,当前访问线程数:{_currentAccessCount}");
            Thread.Sleep(2000); // 模拟资源操作耗时
        }
        finally
        {
            // 释放信号量,一定要放在finally中避免异常导致信号量无法释放
            Interlocked.Decrement(ref _currentAccessCount);
            Console.WriteLine($"线程{threadId}释放资源访问权限,当前访问线程数:{_currentAccessCount}");
            _semaphore.Release();
        }
    }
}

异步场景示例

如果是异步编程场景,可以使用WaitAsync方法避免阻塞线程:

using System;
using System.Threading;
using System.Threading.Tasks;

class AsyncProgram
{
    // 初始化信号量,最多允许2个并发访问
    private static SemaphoreSlim _asyncSemaphore = new SemaphoreSlim(2, 2);

    static async Task Main(string[] args)
    {
        // 启动8个异步任务模拟并发访问
        var tasks = new Task[8];
        for (int i = 0; i < 8; i++)
        {
            int taskId = i;
            tasks[i] = AsyncAccessResource(taskId);
        }

        await Task.WhenAll(tasks);
    }

    static async Task AsyncAccessResource(int taskId)
    {
        Console.WriteLine($"任务{taskId}等待获取资源访问权限");
        // 异步获取信号量,不会阻塞线程
        await _asyncSemaphore.WaitAsync();
        try
        {
            Console.WriteLine($"任务{taskId}获取到权限,开始访问资源");
            await Task.Delay(1500); // 模拟异步资源操作
            Console.WriteLine($"任务{taskId}资源访问完成");
        }
        finally
        {
            // 释放信号量
            _asyncSemaphore.Release();
            Console.WriteLine($"任务{taskId}释放资源访问权限");
        }
    }
}

使用注意事项

在使用SemaphoreSlim的时候需要注意以下几点:

  • 获取信号量的操作一定要和释放操作配对,建议把释放操作放在try-finally块中,避免因为代码异常导致信号量无法释放,引发死锁问题。
  • 初始化的时候初始并发数和最大并发数可以根据实际需求设置,如果需要动态调整最大并发数,可以调用Release方法传入释放的数量,不过要注意不要超过初始化时设置的最大并发数上限。
  • SemaphoreSlim不支持跨进程使用,如果有跨进程的并发控制需求,需要使用传统的Semaphore类。
  • 如果不需要异步支持,优先使用同步的Wait方法,减少异步状态机的开销。

适用场景总结

SemaphoreSlim适合以下场景使用:

  • 限制对数据库、文件、第三方接口等共享资源的并发访问数量,避免资源被过度占用。
  • 控制线程池任务的并发执行数量,避免大量任务同时执行导致系统负载过高。
  • 实现限流功能,比如限制某个接口的每秒请求处理数量。

通过合理使用SemaphoreSlim,可以有效控制多线程场景下的资源访问并发度,提升系统的稳定性和性能。

SemaphoreSlim并发控制资源访问限制.NET多线程修改时间:2026-07-08 04:42:25

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。