Task
同步和异步
说Task之前,先说一个基本概念,异步,正常的程序在执行时会按照调用的先后顺序执行,当一个靠前的方法还没有执行完毕,就不会执行后面的代码,而异步就是让一个方法的执行过程独立出去,当执行一个异步方法或一段异步代码时,这个方法或代码不会占用主线程,而是新创建一个线程与主线程同时执行。这样就可以让那些很耗资源的加载代码异步执行,让主线程空出来做别的事,比如显示加载进度、绘制界面之类的。Task
在Task之前多线程是用ThreadPool实现的,虽然确实能实现多线程,但不能控制线程的执行顺序,也不能获取线程内程序的执行状况(异常或成功),所以.NET4.0在ThreadPool的基础上推出了Task,保留了ThreadPool优点的同时,也解决了ThreadPool的问题。Task线程的创建主要有三种方式:
//1.new方式实例化一个Task,需要通过Start方法启动 Task task = new Task(() => { Thread.Sleep(100); Console.WriteLine($"hello, task1的线程ID为{Thread.CurrentThread.ManagedThreadId}"); }); task.Start(); //2.Task.Factory.StartNew(Action action)创建和启动一个Task Task task2 = Task.Factory.StartNew(() => { Thread.Sleep(100); Console.WriteLine($"hello, task2的线程ID为{ Thread.CurrentThread.ManagedThreadId}"); }); //3.Task.Run(Action action)将任务放在线程池队列,返回并启动一个Task Task task3 = Task.Run(() => { Thread.Sleep(100); Console.WriteLine($"hello, task3的线程ID为{ Thread.CurrentThread.ManagedThreadId}"); }); Console.WriteLine("执行主线程!");
执行结果:
执行主线程!
hello, task2的线程ID为6
hello, task1的线程ID为5
hello, task3的线程ID为4
上面展示的是没有返回值的Task,可以看到Task并没有影响到主进程的执行,程序先执行完了主线程,再执行异步的线程。我们也可以创建有返回值的Task:
static void Main(string[] args) { Task<string> tt1 = t1(); tt1.Start(); Task<string> tt2 = t1(); tt2.Start(); Task<string> tt3 = t1(); Task<string> tt4 = t1(); tt4.Start(); Console.WriteLine("tt1:"+tt1.Result); Console.WriteLine("执行主线程!"); Console.WriteLine("tt2:"+tt2.Result); Console.WriteLine("tt3:"+tt3.Result); Console.WriteLine("tt4:"+tt4.Result); Console.ReadKey(); } public static Task<string> t1() { Thread.Sleep(1000); return new Task<string>(()=> { return "线程ID:" + Thread.CurrentThread.ManagedThreadId; }); }
执行结果:
tt1:线程ID:4
执行主线程!
tt2:线程ID:5
Task.Result可以获得Task委托的执行结果,但会阻塞主线程,因为tt3没有start所以不会返回值,但主线程一直在等待tt3的执行结果,导致了tt4的结果一致没能输出,但实际上tt4已经执行结束了。
Async/await
Async是方法的修饰符,修饰的方法返回值必须为Task、Task<>、void。必须和await一起使用才有意义,而await用在Task委托的前面,效果先看代码:
static void Main(string[] args) { Task<string> tt1 = t1(); tt1.Start(); tt1.Wait(); Console.WriteLine("执行主线程"); Console.WriteLine(t2().Result); Console.ReadKey(); } public static Task<string> t1() { Thread.Sleep(1000); Console.WriteLine("t1:线程ID:" + Thread.CurrentThread.ManagedThreadId); return new Task<string>(() => { return "t1:线程ID:" + Thread.CurrentThread.ManagedThreadId; }); } public static async Task<string> t2() { Task<string> tt2 = Getstr(); await tt2; string str = tt2.Result; return str; } public static Task<string> Getstr() { Thread.Sleep(1000); return Task<string>.Run(() => { return "Getstr"; }); }
输出结果:
t1:线程ID:1
执行主线程
Getstr
Task.wait的效果是让主线程阻塞,等待Task执行完成再继续执行,而await效果相同,不过阻塞的是t2方法,也就是await修饰的方法,到这里可能会有人想,如果让主线程等待其他线程,那不就和同步一样了吗,看上去确实差不多,但await并不会造成线程的阻塞(web程序感觉不到)。
最后需要说的是,线程并不能提升程序的执行速度,只能提升程序的执行效率(吞吐量)。同步异步各有优劣,需要分情况选择。
标签:Task,Console,Thread,线程,WriteLine,async,NET,执行 From: https://www.cnblogs.com/lrplrplrp/p/16759326.html