vlambda博客
学习文章列表

.NET并发编程-异步编程模型下

写给普通:

祝福所有低调善良的技术人

本系列学习在.NET中的并发并行编程模式,实战技巧

本小节开始学习基于任务的函数式并行。本系列保证最少代码呈现量,虽然talk is cheap, show me the code被奉为圭臬,我的学习习惯是,只学习知识点,代码不在当下立马要用的时候不会认真去读的,更何况在大多时候在手机阅读更不顺畅。


上一小节介绍了.NET中的异步支持,以及任务异步模型,异步的取消等。本小节继续介绍下异步的重试和错误处理。


1、异步重试

异步请求有时会因为网络原因等到导致任务失败,重试也许就好了,因为对于任务可以指定次数的重试,两次尝试之间指定时间间隔。

public static async Task<T> Retry<T>(Func<Task<T>> task, int retries,TimeSpan delay, CancellationToken cts = default(CancellationToken)) => await task().ContinueWith(async innerTask => { cts.ThrowIfCancellationRequested(); if (innerTask.Status != TaskStatus.Faulted) return innerTask.Result; if (retries == 0) throw innerTask.Exception ?? throw new Exception(); await Task.Delay(delay, cts); return await Retry(task, retries - 1, delay, cts); }).Unwrap()

Retry异步操作,我们将此方法放在AsyncEx异步扩展静态类中。ThrowIfCancellationRequested检查下是否手动取消了,然后任务成功就返回,任务失败就延迟指定时间启动任务,递减重试次数。知道重试次数耗尽抛出异常。


下面是一个调用实例:


string stockHistory = await AsyncEx.Retry(() => DownloadStockHistory(symbol), 5, TimeSpan.FromSeconds(2));

2、错误处理


重试是一种错误处理机制。重试一直不行呢,就需要切换任务函数执行。使用Otherwise组合器接收两个任务,如果第一个任务失败就执行第二个任务。通过Status判断任务成功与否。

public static Task<T> Otherwise<T>(this Task<T> task, Func<Task<T>> orTask) =>  task.ContinueWith(async innerTask => { if (innerTask.Status == TaskStatus.Faulted) return await orTask(); return await Task.FromResult<T>(innerTask.Result); }).Unwrap();

调用实例如下:

Image image = await Retry(async () => await DownloadImageAsync("Bugghina001.jpg") .Otherwise(async () => await DownloadImageAsync("Bugghina002.jpg")), 5, TimeSpan.FromSeconds(2));

上面静态方法都是在AsyncEx静态帮助类中,以获得更加牢靠的任务执行。


3、再说一句


平常我做桌面开发和少量的web后台,用到并行的地方很少,我们体量没有那么大,一直处理单线程模式中,脑子也是单核的。并行理解确实晦涩难懂,还是应该慢慢熟练,走出安逸圈的过程必定痛苦的,现在有些许的明朗了。


前年说了很多函数组合器,下一节就重点看看这个,能给任务带来多丝滑的体验


    to be contiued!
下集:函数组合器




写给普通:

祝福所有低调善良的技术人

简单快乐