问题1,async/await + Task.Run 与 async/await一路到底(或者说从下至上)有什么区别?
static void Main(string[] args) { DoSomeThingAsync(); Console.ReadLine(); } static async void DoSomeThingAsync() { var users = await Task.Run(() => { return GetList("aa"); }); //输出 users.ForEach(u => { Console.WriteLine(u.NickName); }); } static List<User> GetList(string name) { //Thread.Sleep(2000); var result= new List<User>() { new User() { NickName="aaa1" }, new User() { NickName="aaa2" }, }; return result; }
在我看来async/await + Task.Run或许更好,假如我的api项目是分了很多层,有interface,service,common等等... 用async/await + Task.Run的方式我只需在controller,async action,Task.Run(),而不需要去从上至下都改成async/await。
class Program { static void Main(string[] args) { DoSomeThingAsync(); Console.ReadLine(); } static async void DoSomeThingAsync() { var users = await GetList("aa"); //输出 users.ForEach(u => { Console.WriteLine(u.NickName); }); } public static async Task<List<User>> GetList(string name) { await Task.Delay(2000); var result=new List<User>() { new User() { NickName="aaa1" }, new User() { NickName="aaa2" }, }; return result; } } //接口层 public interface IUserServices { Task<List<User>> GetListAsync(string name); } //接口实现层 public class UserServices : IUserServices { public async Task<List<User>> GetListAsync(string name) { return await Program.GetList("aa"); } }
问题2,web api本来就是多线程了,为什么还要使用async/await?
首先要知道async await解决了什么问题,不要为了异步而异步,针对高密集的cpu计算异步没太大意义,甚至可能有性能损耗。
其次说async await的实现,就以你的代码为例,如果没有async await的话代码执行步骤就不说了,在有async await后就不一样,一旦调用一个async方法,就是告知,这里我可能需要点时间来处理,你先继续往后走吧(比如io操作),这块执行线程就会继续往后跑而不再关心async方法的返回直到看到对应的await后,就停下来等着await对应的task执行完(你async await的代码在编译后会变成一个状态机,这个你可以看下你这段代码在il中的实现),执行完后就会从对应的task展开(unwarp)拿到原始结果(比如你代码中几个await的地方),这里额外就可以回答你第Task和async await的差异,async await的表现是基于Task,但显式的Task会根据TaskScheduler启动线程,而async await不会额外新起线程,async await会从当前可用线程中找空闲的线程来执行,由于所有线程都没闲着(没有所谓的等待,特别是耗时的io等待),因此服务的吞吐量会高很多(适用于高io场景)
其实上面也解释了多线程和async await的差异了,多线程不等同于异步,你拿TaskFactory或者ThreadPool搞一堆线程,它们都做着同步的工作还是会在执行的时候阻塞,线程大量的时间就这样白白浪费在了等待响应上了。