[C#] 谈谈异步编程async await

  为什么需要异步,异步对可能起阻止作用的活动(例如,应用程序访问 Web 时)至关重要。 对 Web 资源的访问有时很慢或会延迟。 如果此类活动在同步过程中受阻,则整个应用程序必须等待。 在异步过程中,应用程序可继续执行不依赖 Web 资源的其他工作,直至潜在阻止任务完成。

  本节将一步一步带领大家理解async和await。

  期间会有

  Hello World,原理介绍,异步会提高程序的运行速度吗,async和await,MVC中的异步Action,以及线程中常涉及到的线程安全和信号量,以及微软提供的异步API

  推荐先看后顶,学的更快!

Hello World

        static void Main(string[] args)
        {
            new Thread(Test) { IsBackground = false }.Start();      //.Net 在1.0的时候,就已经提供最基本的API.
            ThreadPool.QueueUserWorkItem(o => Test());              //线程池中取空闲线程执行委托(方法)
            Task.Run((Action)Test);                                 //.Net 4.0以上可用
            Console.WriteLine("Main Thread");
            Console.ReadLine();
        }

        static void Test()
        {
            Thread.Sleep(1000);
            Console.WriteLine("Hello World");
        }

  

原理

  其实不管是Task,ThreadPool,本质最终都是Thread。只不过微软帮我们在简化线程控制的复杂度。

  线程池是CLR中事先定义好的一些线程。Task取的线程池,只不过在语法上,可以非常方便取返回值。

异步会提高程序的运行速度吗

  多线程会提高程序的效率,不会提高运行速度。

  这就好比这一个任务让前台花1个小时。前台完成10分钟的时候

  打电话给经理,让他安排一个人来干30分钟(new Thread()),他干剩下的20分钟。(创建线程,需要时间,内存资源)

  或者从旁边空闲的同事中(ThreadPool 或 Task),拉一个人过来干30分钟。他干剩下的20分钟。(需要的时间少,资源本来就存在)

  从上看出,异步会让一份任务时间变长。资源消耗更多。但是可以让前台(UI线程)空闲下来,听从领导(用户)指挥。

async和await只是一个标记

  首先看个Demo,

        static void Main(string[] args)
        {
            Task.Run(() =>                                          //异步开始执行
            {
                Thread.Sleep(1000);                                 //异步执行一些任务
                Console.WriteLine("Hello World");                   //异步执行完成标记
            });
            Thread.Sleep(1100);                                     //主线程在执行一些任务
            Console.WriteLine("Main Thread");                       //主线程完成标记
            Console.ReadLine();
        }

  发现执行结果是:

  这个很正常。但是我们希望先执行主线程完成标记,不改动主线程和Task的任务情况下,如何处理?

使用await和async

        static void Main(string[] args)
        {
            Say();                             //由于Main不能使用async标记
            Console.ReadLine();
        }
        private async static void Say()
        {
            var t = TestAsync();
            Thread.Sleep(1100);                                     //主线程在执行一些任务
            Console.WriteLine("Main Thread");                       //主线程完成标记
            Console.WriteLine(await t);                             //await 主线程等待取异步返回结果
        }
        static async Task<string> TestAsync()
        {
            return await Task.Run(() =>
            {
                Thread.Sleep(1000);                                 //异步执行一些任务
                return "Hello World";                               //异步执行完成标记
            });
        }

  1.凡是使用await关键字的方法,都必须打上async标记。

  2.async表示方法内有异步方法,await表示等待异步方法执行完,并取返回值。

  3.调用async方法,会立刻另起线程执行。await只是显示等待线程结束。

MVC中的异步Action

  既然多线程不能提高运行速度,而且每次请求Asp.net程序都是发起一个新的线程,为什么还要用多线程让其“降速”?

  为了提高网站的吞吐量。

  在MVC中,如果采用异步Action,则会像下面情况执行。

  1.请求到达IIS,IIS应用程序池分配一个worker线程用来响应请求。

  2.worker线程,执行异步操作,调用CLR线程池线程处理。

  3.释放worker线程,响应其他请求。

  4.异步操作执行完,w3wp(应用程序池进程)再次分配一个worker线程继续响应。

  上述使用场景中,会获取两次worker 线程,这两次获取的线程可能相同,也可能会不同。如果有比较耗时的任务,非常建议把同步请求转换为异步。

线程安全和信号量

  先举个线程不安全的例子。

        static void Main(string[] args)
        {
            Task.Run((Action)Test);
            Task.Run((Action)Test);
            Console.ReadLine();
        }

        private static void Test()
        {
            if (!IsComplete)
            {
                //todo other
                Thread.Sleep(500);
                Console.WriteLine("执行完成");
                IsComplete = true;
            }
        }

        public static bool IsComplete { get; set; }

  上面的执行结果,这就是线程不安全。(多线程访问同一段代码 产生不确定结果。)

  

如何解决,涉及到线程锁的概念。线程锁会让多线程访问的时候,一次只允许一个线程进入。

线程锁例子

private static readonly object lockObj = new object();
        public static bool IsComplete { get; set; }
        static void Main(string[] args)
        {
            Task.Run((Action)Test);
            Task.Run((Action)Test);
            Console.ReadLine();
        }

        private static void Test()
        {
            lock (lockObj)                              //锁住的必须是引用类型。由于在静态方法中,则锁住静态引用类型。
            {
                if (!IsComplete)
                {
                    //todo other
                    Thread.Sleep(500);
                    Console.WriteLine("执行完成");
                    IsComplete = true;
                }
            }
        }

  

信号量

  线程锁的技术使一块代码只能一个线程进入。信号量的存在,则是让同一块代码指定多个线程进入。

信号量(SemaphoreSlim)例子

static readonly SemaphoreSlim slim = new SemaphoreSlim(2);
        static void Main(string[] args)
        {
            for (int i = 0; i < 5; i++)
            {
                ThreadPool.QueueUserWorkItem(Test, i);
            }
            Console.ReadLine();
        }

        private async static void Test(object i)
        {
            Console.WriteLine("准备执行" + i);
            await slim.WaitAsync();
            Console.WriteLine("开始执行" + i);
            //todo other
            await Task.Delay(1000);
            Console.WriteLine("执行结束" + i);
            slim.Release();
        }

上面执行结果

从 .NET Framework 4.5 和 Windows 运行时中列出的 API 包含支持异步编程的方法。


应用程序区域


包含异步方法的受支持的 API


Web 访问


HttpClientSyndicationClient


使用文件


StorageFileStreamWriterStreamReaderXmlReader


使用图像


MediaCaptureBitmapEncoderBitmapDecoder


WCF 编程


同步和异步操作

作者:Never、C

本文链接:http://www.cnblogs.com/neverc/p/4368821.html

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

如果觉得还有帮助的话,可以点一下右下角的【推荐】,希望能够持续的为大家带来好的技术文章!想跟我一起进步么?那就【关注】我吧。

时间: 2024-08-21 19:50:35

[C#] 谈谈异步编程async await的相关文章

异步编程Async/await关键字

异步编程Async \await 关键字在各编程语言中的发展(出现)纪实. 时间 语言版本 2012.08.15 C#5.0(VS2012) 2015.09.13 Python 3.5 2016.03 ECMAScript 2016 (ES7) C#中的用法和浅层次原理 我是占位代理 Python中的用法,和协程 我是占位代理 Javascript中的说明 我是占位代理,不懂具体用法.

.net 异步编程async &amp; await关键字的思考

C# 5.0引入了两个关键字 async和await,这两个关键字在很大程度上帮助我们简化了异步编程的实现代码,而且TPL中的task与async和await有很大的关系 思考了一下异步编程中的async & await关键字,对两个关键字尤其是await关键字一直很迷糊,因此深入思考了一下.首先借助的示例是:[你必须知道的异步编程]C# 5.0 新特性--Async和Await使异步编程更简单这是博客园一个大牛写的,自己也一直关注这个大神,不得不说,博客园大神很多,而且氛围也很好.我引入了其中

异步编程async/await

什么是异步? 在异步程序中,程序代码不需要按照编写时的顺序严格执行,有时需要一在一个新的线程中运行一部分代码,有时无需创建新的 线程,但是为了更好的利用单个线程的能力,需要改变代码的执行顺序. 进程 启动程序时,系统会在内存中创建一个新的进程.进程是构成运行程序的资源的集合,这些资源包括虚地址空间.文件句柄和许多其他程序运行所需的东西. 线程 在进程内部,系统创建一个称为线程的内核对象,它代表了真正执行的程序.线程是执行线程的简称.一旦线程建立,系统会在Main方法的第一句开始线程的执行. 线程

c#异步编程async await

可以代替协程了 但是需要.net4 版本 unity2017以上版本可以用了 再也可以不用蛋疼的没有返回值的协程了 //异步编程,和Task一起用 async void TestAsync(){ //等待2秒 await Task.Delay(2000); int a = 0; while (a < 20) { //空等待 await Task.Yield();//相当于 yield return null a++; print(a); } print("haha"); } 原文

JavaScript异步编程——Async/Await vs Promise

兼容性 提醒一下各位,Node 现在从版本 7.6 开始就支持 async/await 了.而就在前几天,Node 8已经正式发布了,你可以放心地使用它. 如果你还没有试过它,这里有一堆带有示例的理由来说明为什么你应该马上采用它,并且再也不会回头. Async/await  对于那些从未听说过这个话题的人来说,如下是一个简单的介绍: Async/await 是一种编写异步代码的新方法.之前异步代码的方案是回调和 promise. Async/await 实际上是建立在 promise 的基础上.

[记录]python异步编程async/await实现

from selectors import DefaultSelector, EVENT_READ, EVENT_WRITE import socket from types import coroutine from urllib.parse import urlparse @coroutine def until_readable(fileobj): yield fileobj, EVENT_READ @coroutine def until_writable(fileobj): yield

Async in C# 5.0(C#中的异步编程Async) 蜗牛翻译之第一章

p { display: block; margin: 3px 0 0 0; } --> 写在前面 在学异步,有位园友推荐了<async in C#5.0>,没找到中文版,恰巧也想提高下英文,用我拙劣的英文翻译一些重要的部分,纯属娱乐,简单分享,保持学习,谨记谦虚. 如果你觉得这件事儿没意义翻译的又差,尽情的踩吧.如果你觉得值得鼓励,感谢留下你的赞,祝各位爱技术的园友在今后每一次应该猛烈突破的时候,不选择知难而退.在每一次应该独立思考的时候,不选择随波逐流,应该全力以赴的时候,不选择尽力

.NET4.5 异步编程 async和await

msdn介绍:https://msdn.microsoft.com/zh-cn/library/hh191443.aspx 其实很简单,标记了async的方法为异步方法,从方法的左大括号开始同步执行,直到第一个await出现就开始异步执行,主线程等待,等带await这行代码异步完了再回到主线程,然后继续往下执行. 如果后面又遇到带await语句的,又异步执行,执行完了就回来,继续同步往下.依此类推. 这样做其实就把我们以前编写等待句柄接收信号的代码给省掉了,就一个await就搞定. Visual

异步编程- async和await

html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption