当前位置:首页 > C# > 正文

构建高性能异步系统(C#自定义任务调度器从零实现教程)

在现代 C# 开发中,C#任务调度器 是处理并发、异步和并行任务的核心组件。.NET 框架自带的 TaskScheduler 虽然强大,但在某些特定场景(如游戏开发、嵌入式系统或需要精细控制执行顺序的后台服务)中,我们可能需要一个自定义任务调度逻辑。本文将手把手教你如何从零开始实现一个简单的自定义任务调度器,即使你是 C# 新手也能轻松上手!

构建高性能异步系统(C#自定义任务调度器从零实现教程) C#任务调度器 自定义任务调度 C#多线程编程 .NET任务调度 第1张

为什么需要自定义任务调度器?

默认的 .NET TaskScheduler.Default 使用线程池来执行任务,适用于大多数通用场景。但如果你有以下需求,自定义调度器就显得尤为重要:

  • 限制并发任务数量(例如只允许 2 个任务同时运行)
  • 按优先级顺序执行任务
  • 在特定线程(如 UI 线程)上执行任务
  • 实现自己的任务队列策略(如 FIFO、LIFO 或基于时间片轮转)

这些正是 C#多线程编程 中高级开发者常遇到的问题。

Step 1:继承 TaskScheduler 基类

要创建自定义调度器,必须继承 System.Threading.Tasks.TaskScheduler 抽象类,并重写关键方法:

  • QueueTask(Task task):当任务被启动时调用
  • TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued):尝试在当前线程内联执行任务
  • GetScheduledTasks():返回当前排队的任务(用于调试)

Step 2:实现一个简单的单线程调度器

下面是一个最基础的单线程任务调度器实现,它使用一个专用后台线程顺序执行所有任务:

using System;using System.Collections.Concurrent;using System.Collections.Generic;using System.Threading;using System.Threading.Tasks;public class SingleThreadTaskScheduler : TaskScheduler, IDisposable{    private readonly BlockingCollection<Task> _taskQueue = new();    private readonly Thread _workerThread;    private volatile bool _disposed = false;    public SingleThreadTaskScheduler()    {        // 创建一个后台工作线程        _workerThread = new Thread(ProcessTasks)        {            IsBackground = true        };        _workerThread.Start();    }    // 将任务加入队列    protected override void QueueTask(Task task)    {        if (_disposed) throw new ObjectDisposedException(GetType().Name);        _taskQueue.Add(task);    }    // 尝试内联执行(这里我们不允许内联,强制走队列)    protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)    {        return false; // 不支持内联执行    }    // 返回当前排队的任务(用于调试)    protected override IEnumerable<Task> GetScheduledTasks()    {        return _taskQueue.ToArray();    }    // 工作线程循环处理任务    private void ProcessTasks()    {        foreach (var task in _taskQueue.GetConsumingEnumerable())        {            TryExecuteTask(task);        }    }    public void Dispose()    {        if (!_disposed)        {            _disposed = true;            _taskQueue.CompleteAdding();            _workerThread.Join();            _taskQueue.Dispose();        }    }}

Step 3:使用自定义调度器

现在我们可以像使用默认调度器一样使用它:

class Program{    static async Task Main(string[] args)    {        using var scheduler = new SingleThreadTaskScheduler();        // 创建基于自定义调度器的任务        var task1 = Task.Factory.StartNew(() =>        {            Console.WriteLine($"Task 1 running on thread {Thread.CurrentThread.ManagedThreadId}");            Thread.Sleep(1000);        }, CancellationToken.None, TaskCreationOptions.None, scheduler);        var task2 = Task.Factory.StartNew(() =>        {            Console.WriteLine($"Task 2 running on thread {Thread.CurrentThread.ManagedThreadId}");        }, CancellationToken.None, TaskCreationOptions.None, scheduler);        await Task.WhenAll(task1, task2);        Console.WriteLine("All tasks completed.");    }}

运行结果会显示两个任务都在同一个线程上顺序执行,证明我们的调度器生效了!

进阶:带优先级的调度器

你可以进一步扩展这个调度器,例如使用 PriorityQueue<Task, int>(.NET 6+)来支持优先级。这在 .NET任务调度 的复杂业务场景中非常实用。

总结

通过本文,你已经掌握了如何在 C# 中实现一个基本的自定义任务调度器。虽然真实项目中的调度器可能更复杂(涉及异常处理、取消令牌、性能监控等),但核心思想不变:继承 TaskScheduler 并控制任务的执行方式。

掌握 C#多线程编程C#任务调度器 的底层机制,能让你在构建高性能、高可靠性的 .NET 应用时游刃有余。赶快动手试试吧!