解锁 C# 的并发魔法,探究 SemaphoreSlim 信号量

771 阅读4分钟

前言

在多线程和并发编程中,同步机制是不可或缺的,它帮助我们控制对共享资源的访问,以及管理线程间的协作。C#提供了多种同步原语,其中SemaphoreSlim是一个轻量级的同步原语,用于控制访问有限数量的资源。本文将深入探讨SemaphoreSlim的特点、构造函数、常用方法,并通过实例来展示其用法。

SemaphoreSlim简介

SemaphoreSlim是.NET Framework中System.Threading命名空间下的一个类,它提供了一个信号量机制,允许多个线程同时访问一定数量的资源。与Semaphore类相比,SemaphoreSlim是一个更轻量级的版本,专为需要高性能的场景设计,它主要适用于任务和异步编程。

SemaphoreSlim的特点

轻量级SemaphoreSlim提供了一个简单而高效的信号量机制,相较于Semaphore,它在性能上有所优化,特别是在同一进程内部使用时。

灵活性:支持同步和异步的等待操作,使得它在异步编程中非常有用。

限制并发访问:可以限制对共享资源或共享操作的并发访问数量,从而实现对资源的有效管理。

SemaphoreSlim的构造函数

SemaphoreSlim提供了三个构造函数:

1、SemaphoreSlim(int initialCount):初始化SemaphoreSlim的实例,设置初始的信号量计数。

2、SemaphoreSlim(int initialCount, int maxCount):初始化SemaphoreSlim的实例,设置初始的信号量计数和最大信号量计数。

3、SemaphoreSlim(int initialCount, int maxCount, CancellationToken cancellationToken):此构造函数不存在。SemaphoreSlim不直接在构造函数中支持CancellationToken,但其WaitAsync方法支持。

SemaphoreSlim的常用方法

WaitWaitAsync:请求进入信号量,如果当前计数大于0,则进入并将计数减1;如果计数为0,则等待直到其他线程释放信号量。

Release:释放信号量,将计数增加指定的值。

Dispose:释放SemaphoreSlim使用的所有资源。

使用 SemaphoreSlim 控制访问

基本用法

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

class Program
{
    static SemaphoreSlim semaphoreSlim = 
    new SemaphoreSlim(3); 
    // 最多允许3个线程同时访问

    static void AccessDatabase(string name, 
    int seconds)
    {
        Console.WriteLine($"{name}
        waits to access a database.");
        semaphoreSlim.Wait();

        Console.WriteLine($"{name} 
        is accessing the database.");
        Thread.Sleep(TimeSpan
        .FromSeconds(seconds)); 
        // 模拟数据库访问
        Console.WriteLine($"{name} is done.");

        semaphoreSlim.Release();
    }

    static void Main(string[] args)
    {
        for (int i = 1; i <= 5; i++)
        {
            int id = i;
            Task.Run(() => 
            AccessDatabase($"Task {id}", id));
        }

        Console.ReadLine();
    }
}

这个例子创建了一个SemaphoreSlim实例,允许最多3个线程同时访问数据库。通过WaitRelease方法,我们控制了对数据库访问的并发数。

异步用法

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

class Program
{
    static SemaphoreSlim semaphoreSlim = new SemaphoreSlim(3); 
    // 最多允许3个任务同时执行

    static async Task 
    AccessResourceAsync(string name, int seconds)
    {
        Console.WriteLine($"{name} 
        waits to access a resource.");
        await semaphoreSlim.WaitAsync();

        Console.WriteLine($"{name} 
        is accessing the resource.");
        await Task.Delay
        (TimeSpan.FromSeconds(seconds)); 
        // 模拟异步操作
        Console.WriteLine($"{name} 
        is done.");

        semaphoreSlim.Release();
    }

    static async Task Main
    (string[] args)
    {
        Task[] tasks = new Task[5];
        for (int i = 1; i <= 5; i++)
        {
            int id = i;
            tasks[i - 1] = 
            AccessResourceAsync($"Task {id}", id);
        }

        await Task.WhenAll(tasks);

        Console.WriteLine("All 
        tasks have been completed.");
    }
}

在这个异步示例中,我们使用WaitAsync方法替代了Wait方法,以非阻塞的方式等待信号量。这对于异步编程场景特别有用,因为它避免了在等待时阻塞线程。

总结

SemaphoreSlim是C#中一个非常有用的同步原语,它提供了一种高效的方式来控制对共享资源的并发访问。通过上述示例,我们可以看到SemaphoreSlim在同步和异步编程中的应用。掌握SemaphoreSlim的使用,对于开发高效、可靠的多线程和异步应用程序至关重要。

最后

如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。

也可以加入微信公众号 [DotNet技术匠] 社区,与其他热爱技术的同行一起交流心得,共同成长!

优秀是一种习惯,欢迎大家留言学习!

作者:技术老小子

出处:mp.weixin.qq.com/s/cGacywr93XrxUXVn5th6EA

声明:网络内容,仅供学习,尊重版权,侵权速删,歉意致谢!