Task from .net 4.0
Task简介
为什么要有Task?
Thread:容易造成时间和空间的开销,而且使用不当容易造成线程过多,导致时间片切换
ThreadPool:控制能力比较弱,比如做Thread的延续,阻塞,取消,超时等功能不能实现,ThreadPool的控制权在CLR,而不在自己。
Task => Thread + ThreadPool + 优化 + 功能扩展
Task看起来像一个Thread,但是在ThreadPool的基础上进行封装并做了性能优化。.net 4.0之后,微软极力推荐Task作为异步计算。
Task的启动方式
启动方式一:实例化方式启动Task
Task task = new Task(()=>
{
Console.WriteLine("tid={0}", Thread.CurrentThread.ManagedThreadId);
});
task.Start();
启动方式二:TaskFactory的方式启动Task
var task = Task.Factory.StartNew(()=>
{
Console.WriteLine("tid={0}", Thread.CurrentThread.ManagedThreadId);
});
启动方式三:Task.Run()的方式启动Task
var task = Task.Run(()=>
{
Console.WriteLine("tid={0}", Thread.CurrentThread.ManagedThreadId);
});
启动方式四:同步执行Task
Task task = new Task(()=>
{
Console.WriteLine("tid={0}", Thread.CurrentThread.ManagedThreadId);
});
task.RunSynchronously ();
Task和ThreadPool
Task底层是由不同的TaskSchedule支撑的,TaskSchedule相当于Task的CPU。默认的TaskSchedule是ThreadPoolScheduler,WPF中的TaskSchedule是SynchronizationContextTaskScheduler, TaskSchedule可以自己定义。
Task的阻塞和延续
阻塞
有以下两个task
Task task1 = new Task(()=>
{
Thread.Sleep(1000);
Console.WriteLine("t1");
});
Task task2 = new Task(() =>
{
Thread.Sleep(2000);
Console.WriteLine("t2");
});
task1.Start();
task2.Start();
var tasks = new Task[2] { task1, task2 };
(1)WaitAll方法 必须其中所有的Task执行完成才算完成
Task.WaitAll(tasks);
Console.WriteLine("main");
输出顺序为:t1 t2 main
(2)WaitAny方法 只要其中一个Task执行完成就算完成
Task.WaitAny(tasks);
Console.WriteLine("main");
输出顺序为:t1 main t2。
(3)Wait方法 等待操作,用法和效果等同于thread.Join()
上面三个方法的返回值都是void。那么,如果不想阻塞主线程实现WaitAll操作,该怎么做?
t1 t2执行完了执行t3,这就是延续的概念。
阻塞
(1)WhenAll方法
Task.WhenAll(tasks).ContinueWith(new Action<Task>(t=>
{
Console.WriteLine("t3");
}));
输出顺序为:t1 t2 t3。且主线程没有被阻塞。
(2)WhenAny方法
Task.WhenAny(tasks).ContinueWith(new Action<Task>(t=>
{
Console.WriteLine("t3");
}));
输出顺序为:t1 t3 t2。且主线程没有被阻塞。
(3)ContinueWhenAll方法:效果同WhenAll
Task.Factory.ContinueWhenAll(tasks, t =>
{
Console.WriteLine("t3");
});
(4)ContinueWhenAny方法:效果同WhenAny
Task.Factory.ContinueWhenAny(tasks, t =>
{
Console.WriteLine("t3");
});