前言:前面有篇从应用层面上面介绍了下多线程的几种用法,有博友说到了async, await等新语法。确实,没有异步的多线程是单调的、乏味的,async和await是出现在C#5.0之后,它的出现给了异步并行变成带来了很大的方便。异步编程涉及到的东西还是比较多,本篇还是先介绍下async和await的原理及简单实现。
  了解异步之前,我们先来看看Thread对象的升级版本Task对象:
  1、Task对象的前世今生:Task对象是.Net Framework 4.0之后出现的异步编程的一个重要对象。在一定程度上来说,Task对象可以理解Thread对象的一个升级产品。既然是升级产品,那它肯定有他的优势,比如我们上面Thread对象不能解决的问题:对于有返回值类型的委托。Task对象能简单的解决。
static void Main(string[] args)
{
Console.WriteLine("执行GetReturnResult方法前的时间:" + DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));
var strRes = Task.Run<string>(() => { return GetReturnResult(); });
//启动Task执行方法
Console.WriteLine("执行GetReturnResult方法后的时间:" + DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));
Console.WriteLine(strRes.Result);
//得到方法的返回值
Console.WriteLine("得到结果后的时间:" + DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));
Console.ReadLine();
}
static string GetReturnResult()
{
Thread.Sleep(2000);
return "我是返回值";
}
  先来看结果:

  从结果分析可知在执行var strRes = Task.Run<string>(() => { return GetReturnResult(); })这一句后,主线程并没有阻塞去执行GetReturnResult()方法,而是开启了另一个线程去执行GetReturnResult()方法。直到执行strRes.Result这一句的时候主线程才会等待GetReturnResult()方法执行完毕。为什么说是开启了另一个线程,我们通过线程ID可以看得更清楚:
staticvoidMain(string[]args)
{
Console.WriteLine("执行GetReturnResult方法前的时间:"+DateTime.Now.ToString("yyyy-MM-ddhh:MM:ss"));
varstrRes=Task.Run<string>(()=>{returnGetReturnResult();});
Console.WriteLine("执行GetReturnResult方法后的时间:"+DateTime.Now.ToString("yyyy-MM-ddhh:MM:ss"));
Console.WriteLine("我是主线程,线程ID:"+Thread.CurrentThread.ManagedThreadId);
Console.WriteLine(strRes.Result);
Console.WriteLine("得到结果后的时间:"+DateTime.Now.ToString("yyyy-MM-ddhh:MM:ss"));
Console.ReadLine();
}
staticstringGetReturnResult()
{
Console.WriteLine("我是GetReturnResult里面的线程,线程ID:"+Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(2000);
return"我是返回值";
}
  结果:

  由此可以得知,Task.Run<string>(()=>{}).Reslut是阻塞主线程的,因为主线程要得到返回值,必须要等方法执行完成。
  Task对象的用法如下:
//用法一
Task task1 = new Task(new Action(MyAction));
//用法二
Task task2 = new Task(delegate
{
MyAction();
});
//用法三
Task task3 = new Task(() => MyAction());
Task task4 = new Task(() =>
{
MyAction();
});
task1.Start();
task2.Start();
task3.Start();
task4.Start();
  由上可知,Task对象的构造函数传入的是一个委托,既然能传入Action类型的委托,可想而知Action的16中类型的参数又可以派上用场了。于是乎Task对象参数的传递不用多说了吧。