任务调度器
任务调度器是将任务和线程联系起来的一个关键纽带。任务调度器的主要职责就是负责将任务指派给相应的工作线程处理。任务并行框架中有一个抽象类TaskScheduler来完成任务调度的工作。如果我们想自定义的任务调度器我们只需要继承该类,并实现一些接口。任务调度器有两个关键接口函数QueueTask和TryExecuteTask ,QueueTask函数主要让任务并行框架将任务项传递给任务调度器。TryExecuteTask函数主要负责通知工作线程执行任务。
下例是我们实现的一个简单的自定义任务调度器:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
namespace DotNetLearning
{
//自定义任务调度器
public class CustomTaskScheduler :TaskScheduler,IDisposable
{
Thread[] dispatchthreads;
BlockingCollection<Task> worktasks;
int concurrentlevel;
//构造函数
public CustomTaskScheduler(int concurentnum)
{
//定义分发线程集合和任务集合
dispatchthreads = new Thread[concurentnum];
worktasks = new BlockingCollection<Task>();
this.concurrentlevel = concurentnum;
//开启任务分发线程
for (int i = 0; i < concurentnum; i++)
{
dispatchthreads[i] = new Thread(() =>
{
//执行任务
foreach (Task task in worktasks.GetConsumingEnumerable())
this.TryExecuteTask(task);
});
dispatchthreads[i].Start();
}
}
//对任务排队
protected override void QueueTask(Task task)
{
//判断任务是否为长时间执行任务
if (task.CreationOptions == TaskCreationOptions.LongRunning)
{
new Thread(()=>{
this.TryExecuteTask(task);
}).Start();
}
else
{
this.worktasks.Add(task);
}
}
//内联执行任务
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
if (dispatchthreads.Contains(Thread.CurrentThread))
{
return TryExecuteTask(task);
}
else
{
return false;
}
}
//最大并发度
public override int MaximumConcurrencyLevel
{
get
{
return this.concurrentlevel;
}
}
//获取调度任务
protected override IEnumerable<Task> GetScheduledTasks()
{
return this.worktasks.ToArray();
}
//完成
public void Finished()
{
this.worktasks.CompleteAdding();
}
//释放资源
public void Dispose()
{
this.worktasks.CompleteAdding();
foreach (Thread t in dispatchthreads)
{
t.Join();
}
}
}
}
在该自定义任务调度器中我们为长时间执行的任务分配了专用工作线程。存放任务集合的数据结构是BlockingCollection,他是线程安全的,在分发线程获取任务的时候,如果没有任务项该集合会阻塞,直到又获取到了任务项。关于任务编程中的数据共享将在之后的文章中介绍。
下面是我们使用自定义调度器的代码:
运行结果:
任务调度器暂时介绍到这里,以后我会介绍其深层次工作原理和模式。
接下来的文章,我将并行循环操作(Parallel.For和Foreach)的使用。以及PLINQ的使用。
欢迎大家提出意见和看法。