导读:本期聚焦于小伙伴创作的《C#如何创建自己的TaskScheduler自定义任务计划程序方法》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《C#如何创建自己的TaskScheduler自定义任务计划程序方法》有用,将其分享出去将是对创作者最好的鼓励。

在.NET的异步编程体系中,TaskScheduler负责控制任务的执行方式,默认的线程池任务调度器虽然能满足大部分基础场景,但在需要限制并发数、绑定特定线程、实现自定义调度策略时,就需要我们手动创建自定义TaskScheduler。

C#如何创建自己的TaskScheduler自定义任务计划程序方法

自定义TaskScheduler的核心原理

TaskScheduler是一个抽象类,位于System.Threading.Tasks命名空间下,所有自定义的任务调度器都需要继承这个类,并重写两个核心方法和一个属性:

  • GetScheduledTasks:返回一个枚举器,用于调试时查看当前调度的所有任务,实际调度中可以不实现具体逻辑
  • QueueTask:当任务需要被调度时,框架会调用这个方法,我们需要在这个方法里实现自己的任务入队和执行逻辑
  • TryExecuteTaskInline:尝试以内联方式执行任务,也就是在当前线程直接执行任务,返回true表示执行成功

实现限制并发数的自定义TaskScheduler

下面我们实现一个最多允许同时执行N个任务的自定义调度器,首先定义调度器类:

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace CustomTaskSchedulerDemo
{
    // 自定义任务调度器,限制最大并发数
    public class LimitedConcurrencyTaskScheduler : TaskScheduler
    {
        // 最大并发数
        private readonly int _maxConcurrency;
        // 当前正在执行的任务数
        private int _runningTasksCount = 0;
        // 待执行的任务队列
        private readonly Queue<Task> _taskQueue = new Queue<Task>();
        // 队列锁,保证线程安全
        private readonly object _lockObj = new object();

        public LimitedConcurrencyTaskScheduler(int maxConcurrency)
        {
            if (maxConcurrency < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(maxConcurrency), "最大并发数必须大于等于1");
            }
            _maxConcurrency = maxConcurrency;
        }

        // 重写调度任务方法
        protected override void QueueTask(Task task)
        {
            lock (_lockObj)
            {
                // 将任务加入队列
                _taskQueue.Enqueue(task);
                // 尝试执行队列中的任务
                TryExecuteNextTask();
            }
        }

        // 尝试执行下一个任务
        private void TryExecuteNextTask()
        {
            // 如果当前执行数达到上限,或者队列为空,直接返回
            if (_runningTasksCount >= _maxConcurrency || _taskQueue.Count == 0)
            {
                return;
            }

            // 从队列取出任务
            Task task = _taskQueue.Dequeue();
            // 增加正在执行的任务计数
            Interlocked.Increment(ref _runningTasksCount);

            // 在线程池线程执行任务
            ThreadPool.QueueUserWorkItem(_ =>
            {
                try
                {
                    // 执行任务
                    TryExecuteTask(task);
                }
                finally
                {
                    // 任务执行完成后减少计数
                    Interlocked.Decrement(ref _runningTasksCount);
                    // 再次尝试执行队列中的下一个任务
                    lock (_lockObj)
                    {
                        TryExecuteNextTask();
                    }
                }
            });
        }

        // 重写内联执行任务方法,这里不实现内联执行,直接返回false
        protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
        {
            return false;
        }

        // 重写获取调度任务的方法,用于调试
        protected override IEnumerable<Task> GetScheduledTasks()
        {
            lock (_lockObj)
            {
                return _taskQueue.ToArray();
            }
        }
    }
}

自定义TaskScheduler的使用方式

创建好自定义调度器之后,我们可以通过TaskFactory或者Task的Start方法指定使用我们的调度器:

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

namespace CustomTaskSchedulerDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            // 创建最大并发数为2的自定义调度器
            LimitedConcurrencyTaskScheduler scheduler = new LimitedConcurrencyTaskScheduler(2);
            // 创建基于自定义调度器的TaskFactory
            TaskFactory factory = new TaskFactory(scheduler);

            // 创建10个任务
            for (int i = 0; i < 10; i++)
            {
                int taskId = i;
                factory.StartNew(() =>
                {
                    Console.WriteLine($"任务{taskId}开始执行,线程Id:{Thread.CurrentThread.ManagedThreadId}");
                    Thread.Sleep(1000);
                    Console.WriteLine($"任务{taskId}执行完成");
                });
            }

            Console.WriteLine("所有任务已提交,等待执行完成");
            Console.ReadLine();
        }
    }
}

运行上面的代码,你会看到最多同时只有2个任务在执行,符合我们自定义调度器的并发限制逻辑。

自定义TaskScheduler的注意事项

  • 自定义调度器中的队列操作和计数修改都需要做好线程同步,避免多线程操作导致的异常
  • 如果任务执行过程中抛出异常,不会影响调度器的后续运行,但是需要业务层自行处理任务异常
  • TryExecuteTaskInline方法如果返回true,框架就不会再调用QueueTask方法,需要根据实际场景决定是否实现内联执行逻辑
  • 不要在QueueTask方法中阻塞线程,否则会影响任务提交的效率

适用场景说明

自定义TaskScheduler除了限制并发数之外,还可以实现很多其他场景:比如指定所有任务都在UI线程执行,适合WPF、WinForm的UI更新场景;或者实现定时调度,让任务在指定的时间点执行;还可以实现任务优先级调度,让高优先级的任务先执行。只要理解了核心的调度逻辑,就可以根据业务需求扩展出各种符合场景的调度策略。

C#TaskScheduler自定义任务计划异步编程任务调度修改时间:2026-07-24 01:42:27

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