关于TaskFactory,上面的例子中我们使用了System.Threading.Tasks .Task.Factory属性来快速的创建Task。当然你也可以自己创建TaskFactory,你可以指定自己的TaskCreationOptions,TaskContinuationOptions来使得通过你的Factory创建的Task默认行为不同。
.Net中有一些默认的创建Task的方式,由于TaskFactory创建Task的默认行为不同可能会导致一些不容易发现的问题。
如在.NET 4.5中,Task加入了一个Run的静态方法:
Task.Run(someAction);
如果你用这个方法代替上面例子中的Task.Factory.StartNew,就无法得到正确的结果。原因是Task.Run创建Task的行为默认是默认是拒绝添加子任务的。上面的代码等价于:
Task.Factory.StartNew(someAction, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
你也可以创建具有自己默认行为的TaskFactory。
无论ThreadPool也好,或者Task,微软都是在想进办法来实现线程的重用,来节省不停的创建销毁线程带来的开销。线程池内部的实现可能在不同版本中有不同的机制。如果可能的话,使用线程池来管理线程仍然是建议的选择。
我们主要介绍了一下Task的基本用法,在我们编程过程中,有一些使用Task来提升程序性能的场景往往是很相似的,微软为了简化编程,在System.Threading.Tasks.Parallel中封装了一系列的并行类,内部也是通过Task来实现的。
Parallel的For,Foreach,Invoke 方法
在编程过程中,我们经常会用到循环语句:
for (int i = 0; i < 10; i++)
{
DoSomeWork(i);
}
如果循环过程中的工作可以是并行的话,那么我们可以用如下语句:
Parallel.For(0, 10, i => DoSomeWork(i));
我们也经常会使用Foreach来遍历某个集合:
foreach (var item in collection)
{
DoSomeWork(item);
}
如果我们用一个线程池来执行里面的任务,那么我们可以写成:
Parallel.ForEach(collection, item => DoSomeWork(item));
最后,如果你想并行的执行几个不同的方法,你可以:
Parallel.Invoke(Method1, Method2, Method3);