一.异步方法:用async关键字修饰的方法
1.异步方法的返回值一般是Task,T是返回类型,Task,异步方法以Async结尾.
2.异步方法没有返回值,最好声明为非泛型的Task
3.调用异步方法时加上await,即可获取返回T类型的值
4.异步方法的"传染性":一个方法中如果有await调用,则这个方法必须修饰为async
Example:
static async Task(或者void,尽量写Task) Main(string[] args)
{
string filename="E:\Temp\a.txt";
await File.WriteAllTextAsync(filename,"hello");
string s=await File.ReadAllTextAsync(filename);
}
二.异步方法编写
static async Task Main( [] args)
{
int length=await DownloadHtmlAsync("http://www.baidu.com",@"e:\Temp\a\1.txt");
Console.WriteLine(length);
}
//下面这种写法是不能使用await的时候的写法这种写法不好,还不如自己写多线程
//.Wait()/.Result不要用
static void Main(string[] args)
{
Task<int> strLengthT=File.ReadAllTextAsync(@"e:\Temp\a\1.txt");
int strLength=strLengthT.Result;
Console.WriteLine(strLength);
//不能写Async方法也没有返回值,
//File.WriteAllTextAsync(@"e:\Temp\a\1.txt","aaaaaa").Wait();
}
static async Task<int> DownloadHtmlAsync(string url,string filename)
{
string html="";
using(HttpClient httpClient=new HttpClient)
{
html=await httpClient.GetStringAsync(url);
await File.WriteAllTextAsync(filename,html);
}
return html.Length;
}
线程池中的异步委托使用:下面是lamda表达式:在lamda表达式前加async修饰就可以使用异步编程
static void Main(string[] args)
{
ThreadPool.QueueUserWorkItem(async (obj)=>{
while(true)
{
await File.WriteAllTextAsync(@"e:\Temp\a\1.txt","aaaaaaaa");
Console.WriteLine("xxxxxx");
}
});
Console.Read();
}
三 async与await解密
可用ILSpy反编译器反编译,该代码,可知async的方法会被C#编译器编译成一个类,根据await调用
进行切分为多个状态(swich(){case}),对async方法的调用会被拆分为对MoveNext的调用,await看似等待,经过编译
后,其实没有等待
static async Task Main(string[] args)
{
using(HttpClient httpClient=new HttpClient())
{
string html=await httpClient.GetStringAsync("http://www.baidu.com");
Console.WriteLine(html);
}
string txt ="hello cdc";
string FileName="E:\temp\1.txt";
await File.WriteAllTextAsync(FileName,txt);
Console.WriteLine("写入成功!");
string s =await File.ReadAllTextAsync(FileName);
Console.WriteLine("文件内容:"+s);
}
四:async背后的线程切换
await调用的等待期间,.Net会把当前的线程返回会给线程池,等异步方法调用执行完毕之后,
框架会从线程池再取出一个线程来执行后续的代码,如果下面的代码sb很短,则不会切换线程,
在编写代码时应该尽量避免切换线程
static async Task Main(string[] args)
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
StringBulider sb=new StringBulider();
for(int i=0;i<10000;i++)
{
sb.Append("cdc");
}
await File.WriteAllTextAsync(@"E:\temp\1.txt",sb.ToString());
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
}
五.接口中的异步方法
async是提示编译器为异步方法中的await代码进行分段处理的,而一个异步方法是否修饰了async对于方法的调用者来讲是没有区别的,因为接口没有方法的实现,所以接口中的方法或者抽象方法不能修饰为async.
yield:用法也不能使用async修饰