c# async await的使用方式及为啥要用它

c# 5的语法(.net framework 4.5+ 版本)引入了 async await的概念,再加上前端开发也经常出现这个概念。用的少,理解也不深,看到了一篇很容易入门的文章,所以在此写一些自己的理解:

 

本文来源于知乎的一篇文章,但是添加了一些自己的测试代码。知乎文章的链接如下

https://zhuanlan.zhihu.com/p/138805565

 

先来看一下顺序执行的例子

        internal static void Test()
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            Task task = new Task(CallMethod);
            //Task task = new Task(CallMethodAsync);
            task.Start();
            task.Wait();


            sw.Stop();
            Console.WriteLine("程序运行共 耗时:" + sw.ElapsedMilliseconds);
            Console.ReadLine();
        }

        static async void CallMethod()
        {
            Console.WriteLine(" Other Work 1111");
            string filePath = "d:\\sampleFile.txt";
            int a = ReadFile(filePath);

            Console.WriteLine(" Other Work 1");
            Thread.Sleep(1000);
            Console.WriteLine(" Other Work 2");
            Thread.Sleep(1000);
            Console.WriteLine(" Other Work 3");

            int length = a;
            Console.WriteLine(" Total length: " + length);

            Console.WriteLine(" After work 1");
            Console.WriteLine(" After work 2");
        }


        static int ReadFile(string file)
        {
            int length = 0;

            Console.WriteLine(" File reading is stating");
            using (StreamReader reader = new StreamReader(file))
            {
                // Reads all characters from the current position to the end of the stream asynchronously   
                // and returns them as one string.   
                string s = reader.ReadToEnd();

                length = s.Length;
            }
            Thread.Sleep(2000);
            //Console.WriteLine("Hello world");
            Console.WriteLine(" File reading is completed");
            return length;
        }

程序执行以后,输出如下:

 

 

 

可以看到,因为我在ReadFile 里面进行了延时,所以ReadFile内的函数耗时 + 函数外的耗时  = 4秒 左右

 

再看一下使用async await异步执行的例子

        internal static void Test()
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            //Task task = new Task(CallMethod);
            Task task = new Task(CallMethodAsync);
            task.Start();
            task.Wait();


            sw.Stop();
            Console.WriteLine("程序运行共 耗时:" + sw.ElapsedMilliseconds);
            Console.ReadLine();
        }

        static async void CallMethodAsync()
        {
            Console.WriteLine(" Other Work 1111");
            string filePath = "d:\\sampleFile.txt";
            Task<int> task = ReadFileAsync(filePath);

            Console.WriteLine(" Other Work 1");
            Thread.Sleep(1000);
            Console.WriteLine(" Other Work 2");
            Thread.Sleep(1000);
            Console.WriteLine(" Other Work 3");

            int length = await task;
            Console.WriteLine(" Total length: " + length);

            Console.WriteLine(" After work 1");
            Console.WriteLine(" After work 2");
        }


        static async Task<int> ReadFileAsync(string file)
        {
            int length = 0;

            Console.WriteLine(" File reading is stating");
            using (StreamReader reader = new StreamReader(file))
            {
                // Reads all characters from the current position to the end of the stream asynchronously   
                // and returns them as one string.   
                string s = await reader.ReadToEndAsync();

                length = s.Length;
            }
            Thread.Sleep(2000);
            Console.WriteLine(" File reading is completed");
            return length;
        }

程序输出的结果如下:

 

 可以看到,使用 async await 的异步执行,只花费了2秒左右的时间。

这是为什么呢? 因为使用异步执行时,函数内部已经开启独立的Task 去执行了。所以函数主体依然能够一直运行,直至

            int length = await task;

这一步的时候,因为内外层都是2秒左右的延时,所以无需等待时间,极大地缩短了运行时间。

 

如果我们把 ReadFileAsync 的Sleep时间修改成三秒会发现输出更有意思了

 

 咦? 这里2秒,程序都跑完了,怎么才输出 Total length 以及结束的内容呢?这里就是异步编程的强大之处

如果使用传统的编程,那么这里 2 + 3 =5  秒程序才会结束

而如果使用异步编辑, 2< 3  = 3 秒程序实际就可以结束

 

这样子相比传统顺序执行的编程,那岂不是会有一个问题?函数主体都已经返回了,我却拿不到返回值,这咋整?

其实在ReadFile里面已经提供了范例: 如果要等  CallMethodAsync 的所有异步都结束再退出,可以将CallMethodAsync 改为 ReadFileAsync 的形式,在外层调用

修改之后得到的输出为:

 

 

如果不使用以上的方式,使用传统的编程方式,如何才能缩短执行时间呢?目前我是没想到更好,更优雅的方式……

 

posted on 2022-01-21 14:32  幸福的菜菜  阅读(316)  评论(0编辑  收藏  举报

导航