C#多线程编程笔记(5.4)-对并行执行的异步任务使用await操作符

近来在学习Eugene Agafonov编写的《C#多线程编程实战》(译),做些笔记也顺便分享一下^-^

本篇将学习如何使用await来并行地运行异步任务,而不是采用常用的顺序执行。

using System;
using System.Threading.Tasks;
using System.Threading;

namespace 对并行执行的异步任务使用await操作符
{
    class Program
    {
        static void Main(string[] args)
        {
            Task t = AsynchronousProcessing();
            t.Wait();

            Console.ReadKey();
        }

        async static Task AsynchronousProcessing()
        {
            Task<string> t1 = GetInfoAsync("Task 1", 3);
            Task<string> t2 = GetInfoAsync("Task 2", 5);

            string[] results = await Task.WhenAll(t1, t2);
            foreach (string result in results)
            {
                Console.WriteLine(result);
            }
        }

        async static Task<string> GetInfoAsync(string name,int seconds)
        {
            await Task.Delay(TimeSpan.FromSeconds(seconds));
            //await Task.Run(() => Thread.Sleep(TimeSpan.FromSeconds(seconds)));
            return string.Format("Task {0} is running on a thread id {1}.Is thread pool thread: {2}",
                name, Thread.CurrentThread.ManagedThreadId,
                Thread.CurrentThread.IsThreadPoolThread);
        }
    }
}

程序运行结果如下:


这里我们定义了两个异步任务,分别运行3秒和5秒。然后使用Task.WhenAll辅助方法创建了另一个任务,该任务只有在底层任务完成后才会运行。之后我们等待该组合任务的结果。5秒后,我们获取了所有结果,说明了这些任务是同时运行的。

然而这里观察到一个有意思的现象。当运行该程序时,我们注意到这两个任务似乎是被线程池中的同一个工作线程执行的。当我们并行运行任务时怎么可能发生这样的事情呢?为了让事情更有趣,我们来注释掉GetInfoAsync方法中的await Task.Delay代码行,并解除对await Task.Run代码行的注释,然后再次运行程序。


我们看到该情况下两个任务被不同的工作线程执行。不同之处是Task.Delay在幕后使用了一个计时器,过程如下:从线程池中获取工作线程,它将等待Task.Delay方法返回结果。然后,Task.Delay方法启动计时器并指定一块代码,该代码会再计时器时间到了Task.Delay方法中指定的秒数后被调用。之后立即将工作线程返回到线程池中。当计时器事件运行时,我们又从线程池中任意获取一个可用的工作线程(可能就是运行一个任务时使用的线程)并运行计时器提供给它的代码。

当使用Task.Run方法时,从线程池中获取了一个工作线程并将其阻塞几秒,具体秒数由Thread.Sleep方法提供。然后获取了第二个工作线程并且也将其阻塞。在这种场景下,我们消费了两个工作线程,而它们绝对什么事没做,因为在它们等待时不能执行任何其他操作。

尽可能地使用第一种方式,是创建高伸缩性的服务器程序的关键!


猜你喜欢

转载自blog.csdn.net/qq_35445058/article/details/80926024