译文链接:https://www.infoworld.com/art…
TPL(工作并行库)是 .NET Framework 最新版本中最乏味的新性能之一,在.NET Framework 4.0 中被引入。要应用 TPL,您须要援用 System.Threading.Tasks 命名空间。
什么是 task schedulers?为什么须要它们?
如果我想问,Task 是如何被调度执行的?其实有一个组件叫做 task scheduler,它专门负责调度 task。从实质上来说,这是一个底层对象的形象层,它能够将您的 task 通过排队调度到线程上。
.NET Framework 为您提供了两个 task schedulers。包含基于默认的 task scheduler 用于调度在 Thread Pool 之上,另一个 task scheduler 可能调度在 指定对象的同步上下文上。请留神,TPL 的默认 task scheduler 利用了.NET Framework 线程池。该线程池的示意类 ThreadPool 是在 System.Threading.Tasks 命名空间下。
只管默认的 task scheduler 在大多数状况下已足够,但有时候你兴许也想构建自定义的 task scheduler 去实现个性化的性能,比方那些默认的 task scheduler 没有提供的。此类性能可能包含 FIFO 执行,并发度等。
在 C#中扩大 TaskScheduler
要构建自定义的 task scheduler,您须要创立一个类并继承 System.Threading.Tasks.TaskScheduler。因而,要构建自定义的 task scheduler,您须要扩大 TaskScheduler 抽象类并重写以下办法。
- QueueTask 返回 void 并承受 Task 对象作为参数,当一个 task 须要调度的时候就要调用这个办法
- GetScheduledTasks 返回所有已被调用的 task list,(精确的说是 IEnumerable)
- TryExecuteTaskInline 用于内联形式(即在以后线程上)执行 task。在这种状况下,无需排队即可执行 task
上面的代码段展现了如何继承 TaskScheduler 类来实现咱们自定义的 scheduler。
public class CustomTaskScheduler : TaskScheduler, IDisposable
{ }
正如在本文后面所探讨的,您须要在 CustomTaskScheduler 中重写上面 3 个办法:GetScheduledTasks,QueueTask 和 TryExecuteTaskInline。
public sealed class CustomTaskScheduler : TaskScheduler, IDisposable
{protected override IEnumerable<Task> GetScheduledTasks()
{//TODO}
protected override void QueueTask(Task task)
{//TODO}
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{//TODO}
public void Dispose()
{//TODO}
}
应用 BlockingCollection 来存储 task 对象汇合
当初咱们开始实现自定义的 task scheduler。以下代码段显示了如何利用 BlockingCollection 存储 task 对象的汇合。
public sealed class CustomTaskScheduler : TaskScheduler, IDisposable
{private BlockingCollection<Task> tasksCollection = new BlockingCollection<Task>();
private readonly Thread mainThread = null;
public CustomTaskScheduler()
{mainThread = new Thread(new ThreadStart(Execute));
if (!mainThread.IsAlive)
{mainThread.Start();
}
}
private void Execute()
{foreach (var task in tasksCollection.GetConsumingEnumerable())
{TryExecuteTask(task);
}
}
//Other methods
}
能够着重看看 CustomTaskScheduler 类的构造函数,一个 thread 是如何被创立并且如何开始调度 Execute 办法的。
实现 GetScheduledTasks,QueueTask 和 TryExecuteTaskInline
接下来,咱们须要在 CustomTaskScheduler 中实现三个自定义办法。这三种办法包含 GetScheduledTasks,QueueTask 和 TryExecuteTaskInline。
GetScheduledTasks 办法返回 IEnumerable 类型的 task 汇合, 这样你就能够迭代这个 collection,就像下面 Execute 办法一样。QueueTask 办法承受 Task 对象作为办法参数,而后将其存储在 task collection 中,TryExecuteTaskInline 办法暂不实现,我筹备将它留给读者来实现。
protected override IEnumerable<Task> GetScheduledTasks()
{return tasksCollection.ToArray();
}
protected override void QueueTask(Task task)
{if (task != null)
tasksCollection.Add(task);
}
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{return false;}
残缺的 CustomTaskScheduler 代码如下
上面是最终版本的 CustomTaskScheduler 代码清单:
public sealed class CustomTaskScheduler : TaskScheduler, IDisposable
{private BlockingCollection<Task> tasksCollection = new BlockingCollection<Task>();
private readonly Thread mainThread = null;
public CustomTaskScheduler()
{mainThread = new Thread(new ThreadStart(Execute));
if (!mainThread.IsAlive)
{mainThread.Start();
}
}
private void Execute()
{foreach (var task in tasksCollection.GetConsumingEnumerable())
{TryExecuteTask(task);
}
}
protected override IEnumerable<Task> GetScheduledTasks()
{return tasksCollection.ToArray();
}
protected override void QueueTask(Task task)
{if (task != null)
tasksCollection.Add(task);
}
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{return false;}
private void Dispose(bool disposing)
{if (!disposing) return;
tasksCollection.CompleteAdding();
tasksCollection.Dispose();}
public void Dispose()
{Dispose(true);
GC.SuppressFinalize(this);
}
}
要应用咱们刚刚实现的 CustomTaskScheduler,您能够应用以下代码段:
CustomTaskScheduler taskScheduler = new CustomTaskScheduler();
Task.Factory.StartNew(() => SomeMethod(), CancellationToken.None, TaskCreationOptions.None, taskScheduler);
更多高质量干货:参见我的 GitHub: dotnetfly