async、await、Task这三个,大多数情况下,都是会同时出现的,它们控制着异步代码,简单说你可以理解成一个线程。
有await关键字,就必然会有async,当方法体内会有返回值时,也会必然有Task。
对于调用者来说,他就有两种调用方式:
1.也是调用时加上await关键字,这样在他调用的局部代码中是“同步”的;
2.调用的时候用Task类型来接收,这样就相当于创建了一个非阻塞的线程,执行你的代码,然后代码去干其他事情,等需要返回结果的时候,调用Task的Result属性,若此时异步代码已经执行完,便可以立马拿到返回结果,若还没执行完,则会同步等待返回结果,如果只是调用了异步方法,并没有做任何的await或等待Result的话,则是完全不阻塞的。
而不带async、await、Task的方法,就是普通的同步代码,需要多线程执行时,要么包装到Task中去执行,要么创建一个Thread去执行。
下面简单写个demo程序演示下同步和异步的效果:
public static int DoSomething(string str)
{
Console.WriteLine("同步代码开始,传入的参数是:" + str);
Thread.Sleep(2000);//模拟一些耗时的操作,如读取文件、网络请求等
Console.WriteLine("同步代码结束,传入的参数是:" + str);
return 1;
}
public static async Task<int> DoSomethingAsync(string str)
{
Console.WriteLine("异步代码开始,传入的参数是:" + str);
await Task.Delay(2000);//模拟一些耗时的操作,如读取文件、网络请求等
Console.WriteLine("异步代码结束,传入的参数是:" + str);
return 1;
}
然后不同的调用方式:
var sw = Stopwatch.StartNew();
var sum = DoSomething("sync");
Console.WriteLine("我去做其他的事情,大约需要1s");
Thread.Sleep(1000);
Console.WriteLine("同步代码耗时:" + sw.ElapsedMilliseconds + "ms");
Console.WriteLine("\r\n-----------------------分割线----------------------\r\n");
sw.Restart();
DoSomethingAsync("async1");
Console.WriteLine("异步代码不等待耗时:" + sw.ElapsedMilliseconds + "ms");
Console.WriteLine("\r\n-----------------------分割线----------------------\r\n");
sw.Restart();
var task = DoSomethingAsync("async2");
Console.WriteLine("我先去做其他的事情,大约需要1s");
Thread.Sleep(1000);
var result = task.Result;
Console.WriteLine("异步代码需要等待返回结果的时候耗时:" + sw.ElapsedMilliseconds + "ms");
Console.WriteLine("\r\n-----------------------分割线----------------------\r\n");
sw.Restart();
await DoSomethingAsync("async3");
Console.WriteLine("我先await再去做其他的事情,大约需要1s");
Thread.Sleep(1000);
Console.WriteLine("await异步代码的时候耗时:" + sw.ElapsedMilliseconds + "ms");
运行结果如下:
可以看出:
同步代码是完全的阻塞,按代码先后顺序依次执行的;
而异步不等待的,完全就是非阻塞的;
而Task.Result的形式,则是同步和异步在同时运行,最终耗时以耗时较长的为准;
await异步代码,则和同步的效果是差不多的。