浅谈C#之任务调度TaskScheduler

devtools/2024/9/21 11:26:37/

一、基本介绍

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

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

二、TaskScheduler的作用

调度任务:将任务分配给线程池中的线程执行。

控制并发:通过限制同时执行的任务数量来控制并发级别。

异常处理:虽然不是直接由 TaskScheduler 处理异常,但它通过控制任务的执行环境间接影响了异常的处理方式。

三、TaskScheduler的关键点

默认调度器:大多数情况下,任务默认在 TaskScheduler.Default 调度器上运行,它通常与线程池中的线程关联。

自定义调度器:你可以创建自定义的 TaskScheduler 来控制任务的执行方式,例如,限制任务并发数或在特定的线程上运行任务。

任务调度:你可以使用 TaskScheduler 来调度任务的执行,例如,使用 Task.Run 方法时可以指定调度器。

同步上下文:在 UI 应用程序中,TaskScheduler 通常与 SynchronizationContext 一起使用,以确保任务在正确的线程上执行,例如在 UI 线程上更新 UI 元素。

任务调度器的层次结构TaskScheduler 可以有一个或多个父调度器,这允许你创建复杂的任务调度层次结构。

四、TaskScheduler的简单例子

using System;
using System.Threading.Tasks;class Program
{static void Main(){// 获取默认的任务调度器TaskScheduler defaultScheduler = TaskScheduler.Default;// 创建一个任务Task myTask = new Task(() =>{Console.WriteLine("Task is running on: " + TaskScheduler.Current.ToString());});// 在默认调度器上运行任务myTask.Start(defaultScheduler);// 等待任务完成myTask.Wait();}
}

五、TaskScheduler的完整例子

步骤 1: 创建自定义 TaskScheduler 类

首先,我们需要创建一个继承自 TaskScheduler 的类,并实现必要的方法。

using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;public class LimitedConcurrencyLevelTaskScheduler : TaskScheduler
{private readonly int _maxDegreeOfParallelism;private readonly ConcurrentQueue<Task> _tasks = new ConcurrentQueue<Task>();private readonly CancellationTokenSource _cts = new CancellationTokenSource();private readonly object _lockObject = new object();private int _currentActiveTasks;public LimitedConcurrencyLevelTaskScheduler(int maxDegreeOfParallelism){if (maxDegreeOfParallelism <= 0) throw new ArgumentOutOfRangeException("maxDegreeOfParallelism");_maxDegreeOfParallelism = maxDegreeOfParallelism;}protected override void QueueTask(Task task){_tasks.Enqueue(task);}protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued){return false;}protected override IEnumerable<Task> GetScheduledTasks(){return _tasks;}public void Start(){for (int i = 0; i < _maxDegreeOfParallelism; i++){Thread thread = new Thread(() =>{try{while (!_tasks.IsEmpty || !_cts.Token.IsCancellationRequested){Task task;if (_tasks.TryDequeue(out task)){base.TryExecuteTask(task);}else{Thread.Yield();}}}catch (Exception ex){Console.WriteLine("Thread encountered an exception: " + ex.Message);}});thread.IsBackground = true;thread.Start();}}public void Stop(){_cts.Cancel();}
}

步骤 2: 使用自定义 TaskScheduler

现在我们可以使用这个自定义的 TaskScheduler 来调度任务。

class Program
{static void Main(string[] args){LimitedConcurrencyLevelTaskScheduler scheduler = new LimitedConcurrencyLevelTaskScheduler(2);scheduler.Start();for (int i = 0; i < 10; i++){Task.Run(() => DoWork(i), scheduler);}Console.WriteLine("Press any key to exit...");Console.ReadKey();scheduler.Stop();}static void DoWork(int workItemId){Console.WriteLine($"Work item {workItemId} is running on thread {Thread.CurrentThread.ManagedThreadId}");Thread.Sleep(1000); // Simulate work by sleeping}
}

解释

LimitedConcurrencyLevelTaskScheduler:这是一个自定义的 TaskScheduler,它接受一个参数 maxDegreeOfParallelism,这定义了同时运行的最大任务数。

QueueTask:这个方法将任务添加到一个线程安全的队列中。

TryExecuteTaskInline:这个方法始终返回 false,因为我们不在调用线程上直接执行任务。

GetScheduledTasks:返回当前队列中的任务。

Start:启动指定数量的线程来处理队列中的任务。

Stop:停止所有线程并取消所有任务。


http://www.ppmy.cn/devtools/108501.html

相关文章

(postman)接口测试进阶实战

1.内置和自定义的动态参数 内置的动态参数有哪些&#xff1f; ---{{$}}--是内置动态参数的标志 //自定义的动态参数 此处date.now()的作用就相当于上面的timestamp 2.业务闭环及文件接口测试 返回的url地址可以在网页中查询得到。 3. 常规断言&#xff0c;动态参数断言&#xf…

Vue - 关于Router路由跳转时显示的animate.css动画

Vue - 关于Router路由跳转时显示的animate.css动画 在Vue中&#xff0c;操作路由跳转时页面是闪白的&#xff0c;没有动画效果&#xff0c;我们可以通过在router-view中设置transition&#xff0c;并搭配animate丰富的动画效果来美化路由跳转时的显示效果. 1.安装animate np…

Scratch 变量模块

引言 在编程世界里&#xff0c;变量是一种非常重要的数据存储机制&#xff0c;它允许我们在程序运行过程中保存和处理信息。Scratch 作为一种入门级的编程语言&#xff0c;同样提供了变量功能&#xff0c;使得用户可以轻松地理解和使用变量这一概念。本文将介绍如何在 Scratch …

spring数据校验Validation

文章目录 需要的依赖创建校验对象Validator 需要的依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId> </dependency>创建校验对象Validator 测试的实体类 //创建…

STM32 - 笔记4

1 STM32 示波器 基于STM32的简易示波器项目(含代码)——HAL库_stm32简易示波器 基于STM32的简易示波器项目(含代码)——HAL库_stm32简易示波器_stm32示波器-CSDN博客 【强烈推荐】基于stm32的OLED各种显示实现(含动态图)_stm32oled以十六进制显示-CSDN博客 STM32示波器…

黑马-Cloud21版-面试篇13:Sentinel源码分析

Sentinel源码分析 1.Sentinel的基本概念 Sentinel实现限流、隔离、降级、熔断等功能&#xff0c;本质要做的就是两件事情&#xff1a; 统计数据&#xff1a;统计某个资源的访问数据&#xff08;QPS、RT等信息&#xff09;规则判断&#xff1a;判断限流规则、隔离规则、降级规…

linux如何创建一个空的固定大小的文件

使用dd命令 dd 是一个非常强大的工具&#xff0c;可以用来复制文件和转换文件。你可以使用 dd 来创建一个固定大小的文件。 例如&#xff0c;要创建一个名为example.dat的1GB大小的文件&#xff0c;你可以使用以下命令&#xff1a; dd if/dev/zero ofmyfile bs1M count100if…

9_7_QDial

QDial QSlider 核心属性 //设置刻度线 setNotchesVisible() //设置值&#xff0c;值是整形 setValue() //设置最大范围和最小范围 setMaximum() setMinimum()void Widget::on_dial_valueChanged(int value){ui->label->setText(QString("当前不透明度为:")QS…