异步编程的概念我在第一章概要的时候,说起了。在此再次简略概要一次。编程
它采用future模式或者回调模式机制,以免产生没必要要的线程。
在第一个写这个的缘由,是由于测试可能比开发重要。由于在开发一个项目的时候呢?有一个自动化高效精准测试,决定了上线是否稳定。由于程序出bug测试出来能够改,方案不行换方案,可是测试不行上线了。这时候面临的问题就比较大,由于这时候产生了数据。api
好比说 app 一张表的设计不合理,在自动化测试中没有体现出来,那么你要更换表的时候就显得异常困难,这时候到底换不换表的结构呢?换了以后,如何兼容以前的版本?迭代的方案是啥。好的,扯得很远了。app
固然咱们做为开发人员也要作好单元测试,及子系统测试。好的,近了一点了。异步
咱们在写一个异步程序的时候,是有3个测试必须经过。async
1.同步成功异步编程
2.异步成功单元测试
3.异步失败测试
先介绍一下如何异步测试:url
public static async Task<T> DelayResult<T>(T result, TimeSpan delay) { await Task.Delay(delay); return result; }
如何测试的时候若是这样写:线程
[Fact] public async void Test1() { TimeSpan timeSpan = new TimeSpan(); Program.DelayResult<int>(1, timeSpan); }
那么这个测试是有问题的。
好比:
public static async Task<T> DelayResult<T>(T result, TimeSpan delay) { await Task.Delay(delay); throw new Exception("error"); return result; }
原本我是应该抛出异常的,可是:
结果是下面这样的。
缘由就涉及到一个异常捕获的问题了,能够查询一下原理。
运行测试的时候应该加上await:
[Fact] public async void Test1() { TimeSpan timeSpan = new TimeSpan(); await Program.DelayResult<int>(1, timeSpan); }
那么这个时候就能够捕获到异常。
下面介绍一些例子。
这个是什么意思呢?好比说,咱们访问咱们的一条url的时候,访问失败。
接下来咱们应该作的是重试,那么是否立刻重试?不是的,除非是阻塞式的api调用,例如登陆。
可是呢,若是不是阻塞式的,那么应该把资源分配均衡。由于你一次失败,第二次的也有可能失败。
那么这时候指数退避是一种良好的方法。
static async Task<string> visitUrl(string url) { using (var client = new HttpClient()) { var nextDelay = TimeSpan.FromSeconds(1); for (int i = 0; i != 3; ++i) { try { return await client.GetStringAsync(url); } catch { } await Task.Delay(nextDelay); nextDelay = nextDelay + nextDelay; } // 返回最后的结果方便得出错误 return await client.GetStringAsync(url); } }
测试:
[Fact] public async void Test1() { await Program.visitUrl("www.xxx.com"); }
结果:
测试花了7秒。
正确验证测试我就不测了。
上面的这个代码,咱们发现一个问题啊,若是访问那个连接要很久,那么这也很受伤啊。
是否能加入一个超时,若是访问一段时间没有返回结果,那么把资源留给别的需求者。
public static async Task<string> visitTimeoutUrl(HttpClient client,string url) { var visitTask=client.GetStringAsync(url); var timeoutTask = Task.Delay(3000); var completedTask = await Task.WhenAny(visitTask,timeoutTask); if (completedTask == timeoutTask) { return null; } return await visitTask; }
上文实现了一个简单的超时。
而后改一下:
public static async Task<string> visitUrl(string url) { using (var client = new HttpClient()) { var nextDelay = TimeSpan.FromSeconds(1); for (int i = 0; i != 3; ++i) { try { var result= await visitTimeoutUrl(client,url); if (result != null) { return result; } } catch { } await Task.Delay(nextDelay); nextDelay = nextDelay + nextDelay; } // 返回最后的结果方便得出错误 return await visitTimeoutUrl(client, url); } }
今天写博客的时候,一直出现error,就先到这吧。 下一章,仍是几个例子感觉一下。以上为我的理解,若有不对望请指出。