基于C# SemaphoreSlim 信号量控制位置 在任务内部等待 在任务外部等待 区别?

信号量(SemaphoreSlim)是一种同步原语,用于控制对有限资源的访问。它允许指定数量的线程同时访问某个资源。信号量的使用位置(在任务内部等待还是在任务外部等待)会影响线程的调度和资源的管理。以下通过案例场景解释两者的区别:

场景描述

假设我们有一个系统,限制同时只能有2个任务访问某个资源(如数据库连接或文件系统)。我们使用 SemaphoreSlim(2) 来控制并发访问。


1. 信号量在任务内部等待

var semaphore = new SemaphoreSlim(2);

for (int i = 0; i < 5; i++)
{
    int taskId = i;
    var task = Task.Run(async () =>
    {
        await semaphore.WaitAsync(); // 在任务内部等待信号量
        try
        {
            Console.WriteLine($"任务 {taskId} 开始,获取信号量");
            await Task.Delay(1000); // 模拟耗时操作
        }
        finally
        {
            semaphore.Release(); // 释放信号量
            Console.WriteLine($"任务 {taskId} 结束,释放信号量");
        }
    });
}

await Task.WhenAll(tasks);
特点:
  1. 任务独立性

    • 每个任务在自己的上下文中独立等待信号量。
    • 任务的执行和信号量的获取/释放完全封装在任务内部。
  2. 并发控制

    • 最多允许2个任务同时执行。
    • 当一个任务结束并释放信号量时,下一个等待的任务会立即开始执行。
  3. 适用场景

    • 当任务需要完全独立执行,且信号量的获取和释放逻辑属于任务的一部分时。
    • 例如,多个客户端请求同时访问数据库,每个请求需要独立管理自己的资源获取和释放。
输出顺序(示例):
任务 0 开始,获取信号量
任务 1 开始,获取信号量
任务 0 结束,释放信号量
任务 2 开始,获取信号量
任务 1 结束,释放信号量
任务 3 开始,获取信号量
任务 2 结束,释放信号量
任务 4 开始,获取信号量
任务 3 结束,释放信号量
任务 4 结束,释放信号量

2. 信号量在任务外部等待

var semaphore = new SemaphoreSlim(2);
var tasks = new List<Task>();

for (int i = 0; i < 5; i++)
{
    int taskId = i;
    await semaphore.WaitAsync(); // 在任务外部等待信号量
    var task = Task.Run(async () =>
    {
        try
        {
            Console.WriteLine($"任务 {taskId} 开始");
            await Task.Delay(1000); // 模拟耗时操作
        }
        finally
        {
            semaphore.Release(); // 释放信号量
            Console.WriteLine($"任务 {taskId} 结束");
        }
    });
    tasks.Add(task);
}

await Task.WhenAll(tasks);
特点:
  1. 任务调度控制

    • 信号量的等待发生在任务启动之前。
    • 主线程负责调度任务的启动,确保在信号量允许的情况下才启动新任务。
  2. 并发限制

    • 最多允许2个任务同时执行。
    • 主线程控制任务的启动时机,避免过多任务同时进入等待状态。
  3. 适用场景

    • 当需要对任务的启动进行更精细的控制时。
    • 例如,批量处理任务时,需要限制同时运行的任务数量,以避免资源耗尽。
输出顺序(示例):
任务 0 开始
任务 1 开始
任务 0 结束
任务 1 结束
任务 2 开始
任务 3 开始
任务 2 结束
任务 3 结束
任务 4 开始
任务 4 结束

区别总结

特性信号量在任务内部等待信号量在任务外部等待
任务独立性高,任务完全独立管理信号量的获取和释放低,任务的启动受主线程调度控制
并发控制由信号量自动管理,任务按需获取和释放资源由主线程控制任务启动时机,信号量用于限制资源
适用场景任务需要独立管理资源,如数据库访问需要对任务启动进行精细控制,如批量处理
代码复杂度较低,信号量逻辑封装在任务内部较高,需要在主线程中管理信号量和任务启动
线程调度更灵活,任务可以动态等待和释放资源更严格,任务启动由主线程控制

推荐使用场景

  1. 内部等待

    • 适用于任务需要独立管理资源获取和释放的场景,例如多个客户端请求访问服务器资源。
    • 任务的逻辑封装性更好,适合解耦任务与调度逻辑。
  2. 外部等待

    • 适用于需要对任务启动进行集中控制的场景,例如批处理任务时限制并发数量。
    • 主线程可以更直观地管理资源分配和任务调度。

根据实际需求选择合适的模式,以实现更高效和安全的并发控制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是刘彦宏吖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值