本质上适合异步的操作有:HTTP请求,数据库指令,Web服务调用等。
1、暂停一段时间(以异步方式)。
以异步的方式暂停一段时间,这在进行单元测试或者重试延迟时非常有用。
Task类有一个返回Task对象的静态函数Delay,下面是其中的一个
public static Task Delay(TimeSpan delay) { return Task.Delay(delay, default(CancellationToken)); }
一个简单的指数退避。指数退避是一种重试策略,重试的延迟时间会逐次增加。在访问web服务时可采用指数退避,它可以防止服务器被太多的重试阻塞。
private async Task<string> DownLoadString(string url) { using (var client = new HttpClient()) { //第一次重试前等1秒,第二次重试前等2秒,第三次重试前等4次 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); } }
总结:Task.Delay 适合用于对异步代码进行单元测试或者实现重试逻辑。
2、返回完成的任务 Task.FromResult
当要实现一个既有异步签名的同步方法 或者 对异步代码进行单元测试时,都可以使用Task.FromResult。
Task.FromResult方法创建并返回一个新的Task<T>对象,这个Task对象是已完成,并具有特定的值。
/// <summary>Creates a <see cref="T:System.Threading.Tasks.Task`1" /> that's completed successfully with the specified result.</summary> /// <param name="result">The result to store into the completed task. </param> /// <typeparam name="TResult">The type of the result returned by the task. </typeparam> /// <returns>The successfully completed task.</returns> public static Task<TResult> FromResult<TResult>(TResult result) { return new Task<TResult>(result); }
备注:如果使用Task.FromResult反复调用同一参数,可考虑用一个实际的task变量,以减少垃圾回收的次数。
3、报告进度 IProgress<T> 和 Progress<T>
异步操作执行的过程中,需要展示操作的进度。
使用ProgressChanged 事件来处理进度变化,在异步方法里面使用Report 来报告进度。
var progress = new Progress<double>(); progress.ProgressChanged += Progress_ProgressChanged;
4.等待一组任务完成 Task.WhenAll
当所有任务都完成时,返回一个完成的Task
Task task1 = Task.Delay(TimeSpan.FromSeconds(1)); Task task2 = Task.Delay(TimeSpan.FromSeconds(2)); Task task3 = Task.Delay(TimeSpan.FromSeconds(3)); await Task.WhenAll(task1, task2, task3);
Task<int> task1 = Task.FromResult(3); Task<int> task2 = Task.FromResult(5); Task<int> task3 = Task.FromResult(7); int[] results = await Task.WhenAll(task1, task2, task3);
如果所有任务类型相同,并且全部完成了,Task.WhenAll返回存有每个任务执行结果的数组
5、等待任意任务完成。Task.WhenAny
使用Task.WhenAny方法,该参数是一批任务,当一个任务完成时,就会返回。做为返回的Task就是那个完成的任务。
适用于对一个操作进行多个独立的尝试,只要一个尝试完成,任务就算完成。例如向多个web服务器查询天气等。
private async Task<string> GetStringUrl(string urlA, string urlB) { var httpClient = new HttpClient(); Task<string> taskA = httpClient.GetStringAsync(urlA); Task<string> taskB = httpClient.GetStringAsync(urlB); Task<string> completedTask = await Task.WhenAny(taskA, taskB); return await completedTask; }