亲宝软件园·资讯

展开

并发系列64章(异步编程)第二章

族语1996 人气:0
### 前言 异步编程的概念我在第一章概要的时候,提及了。在此再次简略概要一次。 ``` 它采用future模式或者回调模式机制,以避免产生不必要的线程。 ``` ### 异步编程测试的标准 在第一个写这个的原因,是因为测试可能比开发重要。因为在开发一个项目的时候呢?有一个自动化高效精准测试,决定了上线是否稳定。因为程序出bug测试出来可以改,方案不行换方案,但是测试不行上线了。这时候面临的问题就比较大,因为这时候产生了数据。 比如说 app 一张表的设计不合理,在自动化测试中没有体现出来,那么你要更换表的时候就显得异常困难,这时候到底换不换表的结构呢?换了之后,如何兼容之前的版本?迭代的方案是啥。好的,扯得很远了。 当然我们作为开发人员也要做好单元测试,及子系统测试。好的,近了一点了。 我们在写一个异步程序的时候,是有3个测试必须通过。 1.同步成功 2.异步成功 3.异步失败 先介绍一下如何异步测试: ``` csharp public static async Task DelayResult(T result, TimeSpan delay) { await Task.Delay(delay); return result; } ``` 如何测试的时候如果这样写: ``` csharp [Fact] public async void Test1() { TimeSpan timeSpan = new TimeSpan(); Program.DelayResult(1, timeSpan); } ``` 那么这个测试是有问题的。 比如: ``` csharp public static async Task DelayResult(T result, TimeSpan delay) { await Task.Delay(delay); throw new Exception("error"); return result; } ``` 本来我是应该抛出异常的,但是: ![](https://img2020.cnblogs.com/blog/1289794/202004/1289794-20200403185638664-2054461022.png) 结果是下面这样的。 原因就涉及到一个异常捕获的问题了,可以查询一下原理。 运行测试的时候应该加上await: ``` csharp [Fact] public async void Test1() { TimeSpan timeSpan = new TimeSpan(); await Program.DelayResult(1, timeSpan); } ``` ![](https://img2020.cnblogs.com/blog/1289794/202004/1289794-20200403185955098-1760617658.png) 那么这个时候就可以捕获到异常。 下面介绍一些例子。 ### 指数退避 这个是什么意思呢?比如说,我们访问我们的一条url的时候,访问失败。 接下来我们应该做的是重试,那么是否马上重试?不是的,除非是阻塞式的api调用,例如登录。 但是呢,如果不是阻塞式的,那么应该把资源分配均衡。因为你一次失败,第二次的也有可能失败。 那么这时候指数退避是一种良好的方法。 ``` csharp static async Task 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); } } ``` 测试: ``` csharp [Fact] public async void Test1() { await Program.visitUrl("www.xxx.com"); } ``` 结果: ![](https://img2020.cnblogs.com/blog/1289794/202004/1289794-20200407165708745-340123284.png) 测试花了7秒。 正确验证测试我就不测了。 ### 实现超时功能 上面的这个代码,我们发现一个问题啊,如果访问那个链接要好久,那么这也很受伤啊。 是否能加入一个超时,如果访问一段时间没有返回结果,那么把资源留给别的需求者。 ``` csharp public static async Task 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; } ``` 上文实现了一个简单的超时。 然后改一下: ``` csharp public static async Task 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,就先到这吧。 下一章,还是几个例子感受一下。以上为个人理解,如有不对望请指出。

加载全部内容

相关教程
猜你喜欢
用户评论