.net异步编程async与await

异步编程的好处:

异步编程并不能提速请求响应,它只能增加程序的吞吐量,最大限度的提升线程的利用率。
讨论之前,我们需要了解一个概念:线程池。
线程池微软官方定义:
线程池线程是后台线程。 每个线程均使用默认的堆栈大小,以默认的优先级运行,并且位于多线程单元中。 一旦线程池中的线程完成任务,它将返回到等待线程队列中。 这时开始即可重用它。 通过这种重复使用,应用程序可以避免产生为每个任务创建新线程的开销。每个进程只有一个线程池。
翻译一下就是这个意思:
我们知道一个进程里面有多个线程,但是一个进程只有一个线程池。线程池负责线程的创建和销毁。总之就是负责对线程的分配,相当于线程管理员。
下面我会演示一段代码,使用.net web api 截取的一段代码:

        public async Task<JsonResult> Get()
        {
            Console.WriteLine("GetString方法开始执行");
            GetString();
            Console.WriteLine("GetString方法继续执行");
            Console.WriteLine("GetString方法执行结束");
            return new JsonResult(new string[] { "value1", "value2" });
        }

        public async Task<string> GetString()
        {
            Console.WriteLine("AsyncAction方法await之前");
            string result = await Task<string>.Run(() =>
            {
                Thread.Sleep(1000);
                Console.WriteLine("AsyncAction方法sleep一秒后");
                return "AsyncAction的返回值";
            });
            Console.WriteLine("AsyncAction方法await之后-{0}", result);
            return result;
        }

上面的代码里面,我没有在异步方法加上await,输出的结果如下:在这里插入图片描述
我们可以看到程序一直是顺序执行,直到在遇到await,线程被挂起,接口返回数据之后,才在后台完成了await里面的操作。
应用场景:
这样的实现可以让我们在后台把一些非常耗时的操作写在await里面,而不需要等待他完成的结果,比如说是跟IO有关的操作,接口提前返回数据,让IO耗时操作,在系统后台自动运行,而不用关心结果,像发送短信,写日志,等等这些操作,都可以用这样的方式完成

如果我在代码里面,调用这个异步方法之前,加上await,那么输出的结果又是怎样呢?大家可以猜一下。我贴一下结果。

        [HttpGet]
        public async Task<JsonResult> Get()
        {
            Console.WriteLine("GetString方法开始执行");
            await GetString();
            Console.WriteLine("GetString方法继续执行");
            Console.WriteLine("GetString方法执行结束");
            return new JsonResult(new string[] { "value1", "value2" });
        }

        public async Task<string> GetString()
        {
            Console.WriteLine("AsyncAction方法await之前");
            string result = await Task<string>.Run(() =>
            {
                Thread.Sleep(1000);
                Console.WriteLine("AsyncAction方法sleep一秒后");
                return "AsyncAction的返回值";
            });
            Console.WriteLine("AsyncAction方法await之后-{0}", result);
            return result;
        }

在这里插入图片描述
我们可以看到这已经是相当于同步操作了,加上await,需要等待await函数的执行结果。

        [HttpGet]
        public async Task<JsonResult> Get()
        {
            Console.WriteLine("线程Id:" + Thread.CurrentThread.ManagedThreadId.ToString("00"));
            Console.WriteLine("GetString方法开始执行");
            await GetString();
            Console.WriteLine("GetString方法继续执行");
            Console.WriteLine("GetString方法执行结束");
            return new JsonResult(new string[] { "value1", "value2" });
        }

        public async Task<string> GetString()
        {
            Console.WriteLine("AsyncAction方法await之前");
            string result = await Task<string>.Run(() =>
            {
                Console.WriteLine("处理await的线程ID:" + Thread.CurrentThread.ManagedThreadId.ToString("00"));
                Thread.Sleep(1000);
                Console.WriteLine("AsyncAction方法sleep一秒后");
                return "AsyncAction的返回值";
            });
            Console.WriteLine("AsyncAction方法await之后-{0}", result);
            return result;
        }

在这里插入图片描述
看着像是创建了新线程,其实是由线程池随机分配的线程。
总结:
当函数标记为async的时候,其实是告诉编译器,函数里面可能会有await关键字,异步的关键其实就是这个await,当主线程走到await时,不会新创建一个新线程,去执行await里面的东西,await操作不会创建新线程,而是标记一个回调,等主线程走完,会把线程放到线程池,然后线程池会分配一个空闲的线程处理await的函数,所以处理await函数的前后线程可能是一个线程,有可能不是一个线程,却决于线程池的分配。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章