C#的异步编程是什么?请问js代码块异步执行顺序要怎么写?

199被浏览22,421分享邀请回答void DoA( data , addressOf(DoB) )
ThreadPool.Queue(addressof (DoB));}
void DoB( data , addressOf(DoC) )
ThreadPool.Queue(addressof (DoC));}
void DoC( data )
g0.5 event base:void DoA(data) { blah blahA sync part; RaiseEvent(AFinished,this,eventArg)};
void DoB(data) { blah blahB sync part; RaiseEvent(BFinished,this,eventArg)};
void DoC(data) { blah blahC sync part; RaiseEvent(CFinished,this,eventArg)};
AFinished += (sender,args) =&{ DoB(args); }
BFinished += (sender,args) =&{ DoC(args); }
CFinished += (sender,args) =&{ Output( args); }
包括 promise 和 task 都是上面两种的变形 属于 g1吧,。g1: continue / thenTask DoAAsync(data) { blah blahA sync part;
return asyncExecuteTaskA;)
Task DoBAsync(data) { blah blahB sync part; return asyncExecuteTaskB;};
Task DoC(data) { blah blahC sync part; };
那么就可以写出DoAAsync(data)
.ContinueWith(t=&DoBAsync(t.Result))
.ContinueWith(t=&DoCAsync(t.Result))
上面三个看起来都一样, 基本上是三段逻辑,但是放在三个函数 后来有人觉得不好管理,于是有人写了一个函数 做成了一个状态机 g2:State Machinevoid DoABC( state)
blah blah A sync part:
Thread.Queue(addressof(DoABC) , 1 );
blah blah B sync part;
Thread.Queue(addressof(DoABC) , 2 );
blash C sync Part
加上语法糖就变成了g2.5: async Task DoABCAsync()
Blah A sync part;
blahAsync();
Blah B sync part;
await blahBAsync()
Blah C sync Part;
所以说哪里有等待。并没有。那就自然没有线程阻塞。补充一下,题主 问到 await WhenAll() 了。 如果看懂我上面说的switch state machine的话就可以反编译下whenall 的代码,体会下编译器是怎么写的whenall 的状态机326 条评论分享收藏感谢收起4117 条评论分享收藏感谢收起51CTO旗下网站
让我们再为C#异步编程Async正名
那异步编程是什么情况,能解决什么问题呢?你和你老婆开了一家面包店,在初期只有你俩为顾客服务。没想到新店开张这么火,每分钟来一个顾客,而烤好一份面包需要两分钟。
作者:吴双来源:| 15:05
半年前翻译了一系列很糟糕的异步编程文章,用异步的常用语来说:&在将来的某个时间& 我还会重新翻译Async in C#5.0 。
异步编程在处理并发方面被使用的越来越多,之所以说上面一句话,是为了区分多线程编程。各位司机都知道,实际上异步编程的核心目标正并发处理。可还是经常有一些让人感到很无奈的说法和问题,比如说,异步编程能提高应用性能吗?他能缩短我处理任务的时间吗?他阻塞线程吗?如果不阻塞线程,断点为什么不继续向下执行,我的哥!线程释放到哪儿去了?我都读书少你别骗我,线程都释放了程序怎么运行?前台我用了Ajax,后台使用Async有必要吗?也许如果作为司机的你看到最后一个问题,你只好摊手┑( ̄Д
多线程场景理解
也许在某些时刻,你想提高应用程序执行速度,尽快拿到一个结果。这个时候,应该选择的绝对不是Async和Task。打个比方说,你和你老婆周末去超市购物,刚一进超市门你发现结账的每条队伍都几十人,于是你用到了多线程,你去排队,一个人一个人的往前走,你老婆在另一头抓紧购物,在你快走到收银台的时候,你老婆来把购物车推给了你,于是你们直接结账回家。虽然这种行为很不文明,但这就是多线程,和异步编程一点关系都没有。
&异步编程场景理解
那异步编程是什么情况,能解决什么问题呢?你和你老婆开了一家面包店,在初期只有你俩为顾客服务。没想到新店开张这么火,每分钟来一个顾客,而烤好一份面包需要两分钟。每来一位顾客你都拿着一片面包去后厨烤箱烤,并且你要和你老婆要花两分钟来等各自的烤箱完成任务。可是你等待的这两分钟,又来了两位顾客,着这样的速度下去,根本不能满足顾客们的需求呀!你已经发现你和你老婆的问题了:那就是你和你老婆这两条线程,都被烤箱花费的时间阻塞了!
你和你老婆为了解决阻塞的问题,又买了两台烤箱,并且为了避免新进顾客没人服务,每当你把面包送进烤箱后,标记其属于哪位顾客后立即返回,准备接待新的顾客,再有顾客光临,立马接待,并将新的面包送进另一个烤箱并标记,并立即返回等待为其他人服务。在面包烤好后,烤箱会以&叮&一声,注意在这一信号到达后,并不是一定要你去后厨烤箱取面包,而是你和你老婆谁不忙谁去取。这样处理后,高并发的顾客量,对你来说就显得得心应手了。你和你老婆做为两条线程,可以不断地以非阻塞的形式(不等烤箱),返回到顾客面前。但是需要注意的是不阻塞的概念,他不是让你的程序继续向下执行。就烤面包而言你的一个烤面包方法是这样的:
1.送入面包到烤箱 2.烤箱处理面包并给你结果
3.拿到面包送到顾客。所以说&不阻塞&的概念,不能让你直接做到第三步。在不阻塞期间,是没有线程在你的这个方法中的,这个方法还是要按照时间等待,等待在未来某个时刻的信号唤醒你或者你老婆,此时该方法恢复执行。所以说程序执行的时间依然不变,得到优化的是处理并发的能力,你店里(服务器)的吞吐量。
看着代码理解
&异步编程应当被适用于IO密集型场景,非CPU计算密集场景。大家知道线程受CPU调度,如果你是四核CPU,那么在你的线程池中,拥有四个线程,进程每个虚拟CPU分配一个线程的时候,性能表现会最棒。既能高效运用CPU,又不用来回切换上下文损耗性能。你想想,CPU密集的场景中,CPU就是要占用你的线程,在这个时候异步编程没有任何用处。然而在IO场景中,文件IO由win32用户模式的API到windows内核模式,在内核模式中操作磁盘驱动程序。这期间,你的线程阻塞在驱动程序的响应中。而异步编程中,你的操作通知到磁盘驱动程序后,线程立即返回而非等待,在将来的某个时刻,驱动程序处理结束,处理结果放入CLR线程池队列中,恢复状态机,线程池中任意线程取出结果,方法继续向下执行。在网络IO中也是如此,只不过驱动程序变成了网络驱动程序。请看如下代码:
public&static&async&Task&string&&DoSomeAsync()&&&&&&&&&{&&&&&&&&&&&&&using&(var&client&=&new&HttpClient())&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&var&result&=&await&client.GetAsync(&&&&&&&&&&&&&&&&&&&&&&http://stackoverflow.com/questions//jenkins-configure-page-not-loading-version1-651-3-chrome-browser&)&.Result.Content.ReadAsStringAsync();&Console.WriteLine(result);&//做一些其他操作&var&res&=&1&+&1;&//----------------&return&&&;&&&&&&&&&&&&&}&&&&&&&&&}&
在编译的时候,DosomeAsync会被编译成一个状态机方法,状态机是什么先别管,你可以把它当成一个黑盒子。在遇到GetAsync的时候,在DoSomeAsync中返回一个Task任务对象,并由await在Task对象上传递用于恢复状态机的方法,相当于调用了ContinueWith().这个方法顾名思义,以xxx继续。然后线程从DoSomeAsync中返回。返回后干嘛去了?该线程可以去处理其他事情了。在将来某一时刻,服务器向我们发送了一个相应,网络驱动程序得知请求完毕,恢复该方法继续执行剩下的其他代码。配一张乱糟糟的图
&额外的好处
在GC的垃圾清理执行过程中,应用程序的所有线程都会被挂起,使用异步编程意味着在相同的并发量下,你可以使用更少的线程来完成处理,额外带来的好处就是,所需要清理的线程是更少的。还有一点就是,所使用的线程少了,CPU线程切换也变得更少。
【责任编辑: TEL:(010)】
大家都在看猜你喜欢
头条头条头条头条头条
24H热文一周话题本月最赞
讲师:268498人学习过
讲师:153408人学习过
讲师:91245人学习过
精选博文论坛热帖下载排行
本书分为8章。第1章主要对XML做了简单的介绍。第2章详细讲解规范的XML文件。第3章主要讲解有效的XML文件,特别重点讲解DTD文件。第4章讲解C...
订阅51CTO邮刊他的最新文章
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)267被浏览17,557分享邀请回答241 条评论分享收藏感谢收起public interface IAsyncHandler
Register( Action continuation );
这是伪代码,事实上不存在这么个东西。注册一个回调方法在异步操作完成后继续,所以事实上这段代码的原理像是这样的:private async void btnDoStuff_Click(object sender, RoutedEventArgs e)
btnDoStuff.IsEnabled =
lblStatus.Content = "Doing Stuff";
var handler = Task.Delay(4000) as IAsyncHandler
handler.Register( () =&
lblStatus.Content = "Not Doing Anything";
btnDoStuff.IsEnabled =
当然上面全是伪代码,但是如果你能看懂这段代码在干什么,那么async基本就可以懂了,剩下的只是一些实现细节上的问题。通常情况下,Task.Delay会立即返回一个Task对象,这个Task对象会在指定时间之后被标记为Completed,而被标记Completed就会立即开一个线程来进行延续的操作。但是这里有个问题就是你这个方法是写在UI线程里面的,控件的事件会被UI线程触发,而UI线程上有个SynchronizationContext对象,这个对象的存在就会使得系统在异步回调的时候去捕获源线程。在原来的线程(UI线程)去执行延续的任务。而我们知道WinForm里面有个方法叫做Control.Invoke,可以把一个方法封送到UI线程去执行,而上面的工作和这个方法底层的原理其实是一样的,所以,其实这段代码用传统的思维来理解的话像是这样:private async void btnDoStuff_Click(object sender, RoutedEventArgs e)
btnDoStuff.IsEnabled =
lblStatus.Content = "Doing Stuff";
Action continuation = () =&
lblStatus.Content = "Not Doing Anything";
btnDoStuff.IsEnabled =
Thread.Start( () =&
Thread.Sleep( 4000 );
Control.Invoke( continuation );
3310 条评论分享收藏感谢收起C#异步编程 - 简书
C#异步编程
什么是异步编程
什么是异步编程呢?举个简单的例子:
using System.Net.H
using System.Threading.T
using static System.C
namespace Core
class Async
static void Main()
static void Wait()=&WriteLine("waiting...");
static void End()=&WriteLine("end...");
static int Start()
WriteLine("start...");
HttpClient client = new HttpClient();
Waiting();
var result = client.GetStringAsync("https://www.visualstudio.com/");
string str = result.R
return str.L
上面这段代码中,Main方法中的代码是按照自上而下的顺序执行的。网络状况不佳时,Start()方法是比较耗时(注意,这里在Start方法中调用了异步方法GetStringAsync,但该方法在此处是以同步方式执行的,具体原因下文会进行说明),在Start()方法执行完毕之前,整个程序处于阻塞状态。
而异步编程可以很好的解决这个问题,一句简单的话来概括异步编程就是,程序无须按照代码顺序自上而下的执行。
async/await
C#5.0新增了async和await关键字,使用这两个关键字可以大大简化异步编程
使用 async 关键字可将方法、或标记为异步,即,方法中应该包含一个或多个await表达式,但async关键字本身不会创建异步操作。
public async Task Asy()
这里需要注意一点,若使用async关键字标记的方法中没有使用await关键字(编译器会给出警告但不报错),那么该方法将会以同步方式执行。
定义异步方法的几点要求
定义一个异步方法应满足以下几点:
使用async关键字来修饰方法
在异步方法中使用await关键字(不使用编译器会给出警告但不报错),否则异步方法会以同步方式执行
尽量不使用void作为返回类型,若希望异步方法返回void类型,请使用Task
异步方法名称以Async结尾
异步方法中不能声明使用ref或out关键字修饰的变量
下面定义一个异步方法StartAsync():
static async Task&int& StartAsync()
HttpClient client = new HttpClient();
var str = await client.GetStringAsync("https://www.visualstudio.com/");
return str.L
异步方法的返回类型
如果在调用匿名方法时使用了await关键字,且匿名方法的返回类型是Task&T&,那么我们得到的返回类型是T。若未使用await关键字,则返回类型是Task。
未使用await,调用GetStringAsync方法时result是Task类型
从上图我们可以看到调用GetStringAsync方法时未使用await关键字,result是Task类型,我们可以通过GetType()方法来获取result的详细类型信息:
匿名方法返回类型Task&T&
从上图可以看到result的类型全名是System.Threading.Tasks.Task
使用await关键字,调用GetStringAsync()方法时result是string类型
从上图我们可以看到使用await关键字时,result是string类型,而匿名方法GetStringAsync的返回类型是Task&string&
如果在调用匿名方法时使用了await关键字,且匿名方法的返回类型是Task,那么我们得到的返回类型是void。若为使用await关键字,则得到的返回类型是Task。
不建议使用void作为异步方法的返回值。
因为使用Task或Task&TResult&任务作为返回值,其属性携带有关其状态和历史记录的信息,如任务是否完成、异步方法是否导致异常或已取消以及最终结果是什么。而await运算符可访问这些属性。
异步方法执行流程
异步程序执行流程
上图是微软官方提供的讲解异步程序的图示,并附有解释说明:
The numbers in the diagram correspond to the following steps.
An event handler calls and awaits the AccessTheWebAsync async method.
AccessTheWebAsync creates an
instance and calls the
asynchronous method to download the contents of a website as a string.
Something happens in GetStringAsync that suspends its progress. Perhaps it must wait for a website to download or some other blocking activity. To avoid blocking resources, GetStringAsync yields control to its caller, AccessTheWebAsync.
GetStringAsync returns a
where **TResult **is a string, and AccessTheWebAsync assigns the task to thegetStringTask variable. The task represents the ongoing process for the call to GetStringAsync, with a commitment to produce an actual string value when the work is complete.
Because getStringTask hasn't been awaited yet, AccessTheWebAsync can continue with other work that doesn't depend on the final result from GetStringAsync. That work is represented by a call to the synchronous method DoIndependentWork.
DoIndependentWork is a synchronous method that does its work and returns to its caller.
AccessTheWebAsync has run out of work that it can do without a result from getStringTask. AccessTheWebAsync next wants to calculate and return the length of the downloaded string, but the method can't calculate that value until the method has the string.
Therefore, AccessTheWebAsync uses an await operator to suspend its progress and to yield control to the method that called AccessTheWebAsync. AccessTheWebAsync returns a Task&int& to the caller. The task represents a promise to produce an integer result that's the length of the downloaded string.
If GetStringAsync (and therefore getStringTask) is complete before AccessTheWebAsync awaits it, control remains inAccessTheWebAsync. The expense of suspending and then returning to AccessTheWebAsync would be wasted if the called asynchronous process (getStringTask) has already completed and AccessTheWebSync doesn't have to wait for the final result.
Inside the caller (the event handler in this example), the processing pattern continues. The caller might do other work that doesn't depend on the result from AccessTheWebAsync before awaiting that result, or the caller might await immediately. The event handler is waiting for AccessTheWebAsync, and AccessTheWebAsync is waiting for GetStringAsync.
GetStringAsync completes and produces a string result. The string result isn't returned by the call to GetStringAsync in the way that you might expect. (Remember that the method already returned a task in step Instead, the string result is stored in the task that represents the completion of the method, getStringTask. The await operator retrieves the result from getStringTask. The assignment statement assigns the retrieved result to urlContents.
When AccessTheWebAsync has the string result, the method can calculate the length of the string. Then the work ofAccessTheWebAsync is also complete, and the waiting event handler can resume. In the full example at the end of the topic, you can confirm that the event handler retrieves and prints the value of the length result.
If you are new to asynchronous programming, take a minute to consider the difference between synchronous and asynchronous behavior. A synchronous method returns when its work is complete (step 5), but an async method returns a task value when its work is suspended (steps 3 and 6). When the async method eventually completes its work, the task is marked as completed and the result, if any, is stored in the task.
解释虽是英文,但并没有太难的单词,是可以看懂其意思的。通过上面的说明,我们可以知道:
在遇到awiat关键字之前,程序是按照代码顺序自上而下以同步方式执行的。
在遇到await关键字之后,系统做了以下工作:
异步方法将被挂起
将控制权返回给调用者
使用线程池中的线程(而非额外创建新的线程)来计算await表达式的结果,所以await不会造成程序的阻塞
完成对await表达式的计算之后,若await表达式后面还有代码则由执行await表达式的线程(不是调用方所在的线程)继续执行这些代码
使用一段代码来进行验证:
static void Main()
Task&int& task = StartAsync();
Thread.Sleep(5000);
static async Task&int& StartAsync()
WriteLine("start...");
HttpClient client = new HttpClient();
var result = client.GetStringAsync("https://www.visualstudio.com/");
string str =
return str.L
从上图左侧的调用栈中可以看到,在遇到await关键字之前,异步方法StartAsync自上而下同步执行。注意,这里异步方法GetStringAsync方法是被挂起的,不会造成程序的阻塞,控制权回到调用者StartAsync中,仔细看英文解释中的第3步。
然后在Debug Console中输入System.Threading.Thread.Current查看当前工作线程信息,以及System.Threading.Thread.CurrentThread.IsThreadPoolThread查看当前线程是否在线程池中。
从上图我们看到,当前线程Id是1,不在线程池中。继续执行程序:
遇到await关键字后,异步方法StartAsync被挂起,控制权也回到了调用者Main方法中。
挂起异步方法
从上图我们可以看到异步方法StartAsync中的result变量的Status属性值是WaitingForActivation,Result属性值是Not yet computed。
代码继续执行,将Main方法所在线程接挂起5秒,系统使用线程池中的线程计算await表达式的值:
计算await表达式的值
从上图我们可以看到,程序已经成功计算出await表达式的值,变量result的Status属性值变成了RanToCompletion。完成对await表达式的计算之后,程序继续执行后面的代码(return str.Length)。
再看此时的工作线程信息:
我们看到,当前线程Id是5且存在于线程池中。
从这里我们可以得知异步是借助于多线程来实现的。
类拥有执行异步方法的两个方法:Task.Run(),Task.Run&T&,Task.Run以及Task.Run&T&使用线程池中的线程来执行代码,它和使用await关键字的区别是:Task.Run直接使用线程池中的线程,而使用await的异步方法是在遇到await关键字后才使用多线程。
是前面所说的异步(async/await)和任务(Task)的基础。和线程紧密相关的另外一个概念是进程,这里不多赘述。
ThreadPool
线程也是对象,频繁的创建和销毁线程比较影响性能,.NET提供使得我们能够复用线程对象从而避免频繁创建和销毁线程。
自己创建线程比较麻烦但能够更好的控制程序的运行,使用async/await关键字来编码显得较为简洁,但对程序的控制力度会有所降低。
参考文章:
在通往斜杠青年的路上狂奔
Why Stock Markets CrashThis page intentionally left blankWhy Stock Markets CrashCritical Events in ComplexFinancial SystemsD i d i e r S ...
title标题: A Web Crawler With asyncio Coroutinesauthor作者: A. Jesse Jiryu Davis and Guido van Rossum _A. Jesse Jiryu Davis is a staff engine...
Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智能路由,微代理,控制总线)。分布式系统的协调导致了样板模式, 使用Spring Cloud开发人员可以快速地支持实现这些模式的服务和应用程序。他们将在任何分布式...
cs.AI - 人工智能cs.CL - 计算与语言cs.CR - 加密与安全cs.CV - 机器视觉与模式识别cs.CY - 计算与社会cs.DC - 分布式、并行与集群计算cs.DS - 数据结构与算法cs.HC - 人机接口cs.IR - 信息检索cs.IT - 信息论...
接上文500 Lines or Less:A Web Crawler With asyncio Coroutines异步网络爬虫(一) Coordinating Coroutines We began by describing how we want our crawle...
每一个双十一老婆都会买好几千的东西,我真是头疼,现在就我一个人工作她主要是在家带孩子,一个双十一就用掉我一个多月的工作,今年双十一本身准备好把好关,打死也不打算让她在买这么多东西了。 双十一前一天,我的傻老婆,一个双十一变聪明了居然套路我,不过挺开心。 还准备这个双十一,提...
01 年初,刚上高中的小表弟,突然性情大变:不仅迷上游戏,不能自拔,而且对阿姨的劝说不理不睬,甚至恶语伤人。 阿姨被气得在家里呜呜大哭。跟我妈说:这养得真不是孩子,简直就是养了个祸害啊。 老家迷信,都劝阿姨去给表弟算算命,是不是冲撞了哪一路神仙,毕竟一个好好的孩子突然之间变...
今天想和大家聊聊怎么让PPT更具有设计感。在开始做PPT时,第一时间应该想的是使用什么模板。关键问题是,很多人没有模板,更多人有了模板但是找不到适合自己本次汇报的模板。所以,大多时间,我们做PPT的首要难题是如何自己做一套具有设计感的PPT。今天我就以如何做好一个PPT封面...
白话区块链之谢晗剑谈CITA:目前唯一一个适合云计算的区块链系统 针对企业级用户,而当前其他区块链的设计都是针对个人用户 首个使用微服务机构的区块链系统 把共识和执行分开,独创异步交易处理 独特执行器设计,允许用户混合使用多种智能合约技术 隐私交易加入...

我要回帖

更多关于 java 异步代码块 的文章

 

随机推荐