C# 的TaskScheduler

        在C#中,TaskScheduler 是一个抽象类,用于控制任务的执行方式,特别是它们如何被安排到线程池中的线程上执行。

TaskScheduler 负责将 Task 对象排队并决定何时、以何种方式执行这些任务。

TaskScheduler 的作用

  • 调度任务:将任务分配给线程池中的线程执行。
  • 控制并发:通过限制同时执行的任务数量来控制并发级别。
  • 异常处理:虽然不是直接由 TaskScheduler 处理异常,但它通过控制任务的执行环境间接影响了异常的处理方式。

如何使用 TaskScheduler

        通常,我们不需要直接创建 TaskScheduler 的实例,因为 Task 类和 TaskFactory 类提供了足够的方法来使用默认的 TaskScheduler(通常是 TaskScheduler.Default,它对应于线程池)。

        然而,在某些情况下,你可能需要自定义 TaskScheduler 来满足特定的需求。

示例:使用默认的 TaskScheduler

        大多数情况下,你不需要显式地使用 TaskScheduler,因为 Task.Run 和 Task.Factory.StartNew(当不提供 TaskScheduler 时)默认使用 TaskScheduler.Default

// 使用 Task.Run 启动一个后台任务  
Task.Run(() =>  
{  
    // 这里执行耗时操作  
    Console.WriteLine("任务正在后台执行...");  
    Thread.Sleep(1000); // 模拟耗时操作  
    Console.WriteLine("任务完成.");  
});  
  
// 等待任务完成(仅为了示例,实际代码中通常不会这样做)  
Task.Delay(2000).Wait(); // 确保主线程等待足够长的时间以看到后台任务的结果
示例:自定义 TaskScheduler

        如果你需要自定义任务调度逻辑(例如,限制并发任务的数量),你可以继承 TaskScheduler 并实现其抽象方法。然而,这通常是一个高级用法,需要深入理解多线程编程和 Task 的工作机制。

        这里是一个简化的例子,说明如何继承 TaskScheduler,但请注意,这个例子并没有真正实现任务调度逻辑,而只是展示了如何开始自定义:

public class LimitedConcurrencyTaskScheduler : TaskScheduler  
{  
    // 假设我们有一个限制并发数的字段  
    private readonly int _maxConcurrencyLevel;  
    private int _activeTasks;  
  
    public LimitedConcurrencyTaskScheduler(int maxConcurrencyLevel)  
    {  
        _maxConcurrencyLevel = maxConcurrencyLevel;  
    }  
  
    // 省略了 QueueTask, TryExecuteTaskInline, GetScheduledTasks 等方法的实现  
  
    // 这里只是展示如何开始,实际上你需要实现这些方法来控制任务的调度  
    protected override void QueueTask(Task task)  
    {  
        // 这里应该有逻辑来将任务添加到队列中,并根据需要执行它们  
        // 但由于这是示例,我们只是简单地将任务计数增加  
        Interlocked.Increment(ref _activeTasks);  
  
        // 注意:这实际上并没有真正地将任务排队或执行,只是演示  
  
        // 在真实实现中,你应该在这里将任务放入某种队列中,并在有可用线程时执行它们  
    }  
  
    // ... 其他方法的实现  
}  
  
// 注意:上面的 LimitedConcurrencyTaskScheduler 只是一个框架,并没有完整实现  
// 在实际使用中,你需要完整实现所有抽象方法,并根据需要添加额外的逻辑

        由于自定义 TaskScheduler 的实现相对复杂,且容易出错,因此通常建议仅在我们确实需要控制任务执行的细节时才这样做。在大多数情况下,使用默认的 TaskScheduler 或 Task.Run 就足够了。


补充:

        在C#中,如果有大量task同时执行,假设我们需要限制同时执行的Task的最大数量为5,我们可以通过自定义一个TaskScheduler来实现,但这种方法相对复杂且容易出错。更常见和简单的方法是使用SemaphoreSlim来限制并发量

   SemaphoreSlim是一个轻量级的信号量,用于控制对共享资源的并发访问。你可以使用它来限制同时执行的Task数量。

        下面是一个使用SemaphoreSlim来限制Task最大执行个数的例子:

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Threading;  
using System.Threading.Tasks;  
  
class Program  
{  
    static SemaphoreSlim semaphore = new SemaphoreSlim(5); // 初始化为5,表示同时允许5个任务执行  
  
    static async Task Main(string[] args)  
    {  
        // 假设我们有10个任务需要执行  
        var tasks = Enumerable.Range(1, 10).Select(async i =>  
        {  
            await semaphore.WaitAsync(); // 等待信号量可用  
            try  
            {  
                // 执行任务  
                Console.WriteLine($"任务 {i} 开始执行,当前时间:{DateTime.Now:HH:mm:ss.fff}");  
                await Task.Delay(1000); // 模拟耗时操作  
                Console.WriteLine($"任务 {i} 执行完成,当前时间:{DateTime.Now:HH:mm:ss.fff}");  
            }  
            finally  
            {  
                semaphore.Release(); // 释放信号量  
            }  
        }).ToList();  
  
        // 等待所有任务完成  
        await Task.WhenAll(tasks);  
  
        Console.WriteLine("所有任务执行完成。");  
    }  
}

         在上面这个例子中,我们创建了一个SemaphoreSlim实例,初始化为5,表示同时最多允许5个任务执行。

        然后,我们创建了10个任务,每个任务在执行前都会调用semaphore.WaitAsync()来等待信号量变得可用。当信号量可用时,任务会继续执行,并在执行完毕后通过semaphore.Release()释放信号量,以便其他任务可以执行。

        这种方法简单且有效,不需要我们深入了解TaskScheduler的内部实现,就可以轻松控制并发量。同时,它也避免了自定义TaskScheduler可能带来的复杂性和潜在的错误。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值