异步.异步是在.net .45里面提供的一个新的方法
它主要用在.三个方面
1.网络访问
2.磁盘访问
3.延迟很长时间的步骤
它主要有2个关键字
Async Await
Async 怎么工作
demo_1_下载一个html的2个方式来比较下
public static void Run() { //请注意 输出顺序..over之后才会输出DumpWebPageAsync 里面的page var url = "http://abujj.me"; Console.WriteLine("1"); DumpWebPage(url); Console.WriteLine("2"); DumpWebPageAsync(url); Console.WriteLine("over"); Console.ReadKey(); } // 正常下载 static void DumpWebPage(string uri) { WebClient webClient = new WebClient(); string page = webClient.DownloadString(uri); Console.WriteLine(page.Substring(0,50)); } // 异步下载 static async void DumpWebPageAsync(string uri) { WebClient webClient = new WebClient(); string page = await webClient.DownloadStringTaskAsync(uri); Console.WriteLine(page.Substring(0, 50)); }
如果是异步方法.请后面加入Async后缀..来一标识下
DownloadStringTaskAsync 返回的是
public Task<string> DownloadStringTaskAsync(string address);
了解异步
下面代码是最简单的异步行为..没有用async .把一个回调函数作为参数的一个方法
void GetHostAddress(string hostName, Action<IPAddress> callback)
private void LookupHostName() { GetHostAddress("abujj.me", OnHostNameResolved); } private void OnHostNameResolved(IPAddress address) { // Do something ........ }
上面这个代码 还可以使用匿名方法或者 lamada表达式来实现这个回调
private void LookupHostName() { int aUsefulVariable = 3; GetHostAddress("oreilly.com", address => { // Do something ... }); }
这样写有一个好处.就是在do something里面,可以使用外部的变量值
坏处就是,try_catch 抛异常 不容易控制..
Task(并行)
Task Parallel 库,net是4/0 引入的.async是c#5.0引入的. 里面包含了大量的task 代码.
然后用Task继续更改代码
private void LookupHostName() { Task<IPAddress[]> ipAddressesPromise = Dns.GetHostAddressesAsync("abujj.me"); ipAddressesPromise.ContinueWith(_ => { IPAddress[] ipAddresses = ipAddressesPromise.Result; // Do something ... }); }
它返回一个Task<T> ,当使用ContinueWith 注册回调函数
ContinueWith 函数隶属Task . 意思就是创建一个Task.当完成时,异步执行的延续任务
写Async 代码
从文章开头的webClient就知道大概的async功能.
一步一步分析下这个代码
Task<string> DownloadStringTaskAsync(string address) 返回Task<string>
所以可以这么写
Task<string> myTask =webClient.DownloadStringTaskAsync(uri); // Do something here string page = await myTask;
当第一句话返回Task<string>其实并没有开始下载页面
只有当await的时候.才回去执行下载页面
这样.我们就可以开启多个并行任务.比如
//注册2个任务 Task<string> firstTask = webClient1.DownloadStringTaskAsync("abujj.me"); Task<string> secondTask = webClient2.DownloadStringTaskAsync("abujj.me"); //开始执行 string firstPage = await firstTask; string secondPage = await secondTask
这有个问题.就是如果第一个执行await 抛异常..那么第二个永远不会await了
Async 返回类型
1.void
2.Task
3.Task<T> or T
async 关键字,出现在方法的声明上.就像 public关键字一样 .async 唯一的效果也就是已编译上体现
如果实行继承. async关键字毫无作用..比如
class BaseClass { public virtual async Task<int> AlexsMethod() { ........ } } class SubClass : BaseClass { // 重载 public override Task<int> AlexsMethod() { ... } }
重载后..少了async关键字.
声明接口..不能使用async 关键字 .原因就上上面一样..因为不需要.如果需要返回Task .那实现者可能会选择async
异步 匿名委托
Func<Task<int>> getNumberAsync = async delegate { return 3; };
async lamada :
Func<Task<string>> getWordAsync = async () => "hello";
await
int myNum = await AlexsMethodAsync(await myTask, await StuffAsync());
这个情况,自己可以试验下
什么情况不能用await
1. try-catch
try { page = await webClient.DownloadStringTaskAsync("abujj.me"); } catch (WebException) { page = await webClient.DownloadStringTaskAsync("http://abujj.me"); }
当你抛异常的时候..
正确写法
bool failed = false; try { page = await webClient.DownloadStringTaskAsync("http://abujj.me"); } catch (WebException) { failed = true; } if (failed) { page = await webClient.DownloadStringTaskAsync("http://abujj.me"); }
基于Task_based的异步
前面说道Async用到了大量的Task
原文:http://abujj.me/archives/522