欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

异步编程基础

程序员文章站 2022-10-05 18:23:02
本质上适合异步的操作有:HTTP请求,数据库指令,Web服务调用等。 1、暂停一段时间(以异步方式)。 以异步的方式暂停一段时间,这在进行单元测试或者重试延迟时非常有用。 Task类有一个返回Task对象的静态函数Delay,下面是其中的一个 一个简单的指数退避。指数退避是一种重试策略,重试的延迟时 ......

  本质上适合异步的操作有: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;
        }