手机版

在中使用异步编程的方法步骤 净核心

时间:2021-08-26 来源:互联网 编辑:宝哥软件园 浏览:

最近对异步和多线程编程有一些启发,所以决定写下自己的理解。

思考:为什么要使用异步编程?

我们先来看看同步方法和异步方法之前程序中执行的逻辑:

1.同步方法

静态void main (string [] args) {console。writeline ($' {datetime。现在。tostring(' yyyy-mm-DD hh :mm 3360 ms ')}:start ');//调用同步方法SyncTestMethod();控制台。writeline ($' {datetime。现在。tostring(' yyyy-mm-DD hh :mm : ss ms ')}:end ');控制台。ReadKey();}///summary////同步方法////summary static void synctestmethod(){ for(int I=0;i 10i ) { var str=$'{DateTime。now . ToString(' yyyy-MM-DD hh :MM 3360 ms ')} : sync stmethod { I } ';控制台。WriteLine(字符串);线程。睡眠(10);}}控制台打印:

2019-03-26 14:44:05 445:Start 2019-03-26 14:44:05 4453: SyncTestMethod 02019-03-26 143:433604336005 44533333: SyncTestMethod 12019 36043:05 444444

当主线程调用同步方法时,会直接在主线程中执行同步方法。此时,如果SyncTestMethod方法后面还有其他方法,就需要等待SyncTestMethod的执行完成。

2.异步方法

静态void main (string [] args) {console。writeline ($' {datetime。现在。tostring(' yyyy-mm-DD hh :mm 3360 ms ')}:start ');//调用异步步骤方法AsyncTestMethod();控制台。writeline ($' {datetime。现在。tostring(' yyyy-mm-DD hh :mm 3360 ms ')}:end ');控制台。ReadKey();}///summary////异步方法/////summary//returns/returns static async task async test method(){ await task . run(()={ for(int I=0;i 10i ) {控制台。WriteLine($ ' AsynctMethod ');线程。睡眠(10);} });}控制台打印:

2019-03-26 14:52:37 5237:开始2019-03-26 143:52333:37 5237:结束2019-03-26 143:52:37 5237:async test method 2019-03。AsyncTestMethod 2019-03-26 14:52:37 5237:AsyncTestMethod 2019-03-26 14:37 5237:AsyncTestMethod 2019-03-26 14:523333:37 5237:AsyncTe stmethod 2019-03-26 14333666

当主线程调用异步方法时,它将创建一个新的子线程来执行异步方法。调用AsyncTestMethod后,将直接执行AsyncTestMethod后面的方法。此时,主线程不会等待异步方法的执行完成;此时主线程无法知道异步方法何时执行,因此无法直接在主线程中得到异步方法的返回。如果异步方法执行后需要在主线程中执行其他方法,则需要使用Wait()等待异步子线程执行。

3.等待异步方法

静态void Main(字符串[]参数){控制台.WriteLine($'{DateTime .现在。ToString(' yyyy-MM-DD hh :MM 3360 ms ')}:开始');//调用异步步方法AsyncTestMethod();//等待异步方法执行完成m1 .wait();控制台WriteLine($'{DateTime .现在。ToString(' yyyy-MM-DD hh :MM 3360 ms ')}:结束');控制台ReadKey();}///摘要///异步方法////summary////returns/returns static异步任务AsyncTestMethod(){等待任务.run(()={ for(int I=0;I 10i){ 0控制台WriteLine($'{DateTime .现在。ToString(' yyyy-MM-DD hh :MM 3360 ms ')}:AsyncTestMethod ');线程。睡眠(10);} });}控制台打印:

2019-03-26 14:55:51 5551:开始2019-03-26 14:55:51 5551:async test method 2019-03-26 14:55:51 5551:async test method 2019-03-26 14:533605336053:51 5555551:async method 2019-03-26 143333666结束

主线程在调用异步方法时,将会新建一个子线程去执行异步方法,并且在调用异步测试方法方法之后执行了对异步测试方法方法的等待等等(),这个时候主线程会等待异步方法执行完成,不会执行后续的方法,在异步测试方法执行完成之后,等待结束,此时可以拿到异步方法异步测试方法的返回值,然后再继续执行主线程中的方法。

4.同步线程和异步线程关联执行

如有以下方法:

静态int Method1(){ Thread .睡眠(200);控制台WriteLine($'{DateTime .现在。ToString(' yyyy-MM-DD hh :MM 3360 ms ')}:我计算了一个值耗费200毫秒;返回1;}静态int Method200ms(){ Thread .睡眠(200);控制台WriteLine($'{DateTime .现在。ToString(' yyyy-MM-DD hh :MM 3360 ms ')}:我做了一件耗费200毫秒的事情');返回200;}静态int方法500ms(int索引){ Thread .睡眠(500);控制台WriteLine($'{DateTime .现在。ToString(' yyyy-MM-DD hh :MM 3360 ms ')}:我做了一件耗费500毫秒的事情');收益指数;}静态int Method1000ms(){ Thread .睡眠(1000);控制台WriteLine($'{DateTime .现在。ToString(' yyyy-MM-DD hh :MM 3360 ms ')}:我做了一件耗费1000毫秒的事情');返回1000;}Method500ms()需要方法1()的返回值作为参数,如果所有的方法同步执行在最后计算a、b、c、d的和:

静态void Main(字符串[]参数){控制台.WriteLine($'{DateTime .现在。ToString(' yyyy-MM-DD hh :MM 3360 ms ')}:开始');var a=方法1();var b=方法200 ms();var c=方法500ms(a);var d=方法1000 ms();定义变量结果=a b c d;控制台WriteLine($'{DateTime .现在。ToString(' yyyy-MM-DD hh :MM 3360 ms ')}:最后得到的结果{ result } ');控制台WriteLine($'{DateTime .现在。ToString(' yyyy-MM-DD hh :MM 3360 ms ')}:结束');控制台ReadKey();}控制台打印:

2019-03-26 15:10:06 106:开始2019-03-26 15:10:06 106:我计算了一个值耗费200米2019-03-26 15:10336006 106:我做了一件耗费200毫秒的事情2019-03-26 15:10:07 107:我做了一件耗费500毫秒的事情2019-03-26 15:10:08 108:我做了一件耗费1000毫秒的事情2019-03-26 15:10:08 108:最后得到的结果12032019-03-26 15:10:08 108:结束

同步执行的时候,需要逐一等待所有的方法执行完成,花费的时间显然是所有的方法耗费的时间之和。

对于以上四个方法,如果使用异步的方式来执行,将会很大程度的节省程序的运行时间,修改方法如下:

静态异步任务异步方法1(){等待任务。运行(()={线程。睡眠(200);控制台。writeline ($' {datetime。现在。tostring(' yyyy-mm-DD hh :mm 3360 SSMS ')}:我花了200ms计算一个值');});返回1;}静态异步任务异步方法200毫秒(){等待任务。运行(()={线程。睡眠(200);控制台。writeline ($' {datetime。现在。tostring(' yyyy-mm-DD hh :mm : ss ms ')}:我做了一件花了200ms的事情');});返回200;}静态异步Taskint AsyncMethod500ms(int index){ wait Task。运行(()={线程。睡眠(500);控制台。writeline ($' {datetime。现在。tostring(' yyyy-mm-DD hh :mm : ss ms ')}:我做了一件花了500ms的事情');});收益指数;}静态异步任务异步方法1000毫秒(){等待任务。运行(()={线程。睡眠(1000);控制台。writeline ($' {datetime。现在。tostring(' yyyy-mm-DD hh :mm : ss ms ')}:我做了一件花了1000ms '的事情;});返回1000;}异步调用方法:

静态void main (string [] args) {console。writeline ($' {datetime。现在。tostring(' yyyy-mm-DD hh :mm 3360 ms ')}:start ');var m1=async method 1();var m2=async method 200 ms();var M4=async method 1000 ms();m1。wait();var m3=AsyncMethod50ms(m1。结果);m2。wait();m3。wait();m4。wait();var结果=m1。结果m2。结果m3。结果m4。结果;控制台。writeline ($' {datetime。现在。tostring(' yyyy-mm-DD hh :mm 3360 ms ')}:最终结果{ result } ');控制台。writeline ($' {datetime。现在。tostring(' yyyy-mm-DD hh :mm 3360 ms ')}:end ');控制台。ReadKey();}控制台打印:

2019-03-26 14:11336054 1154:Start 2019-03-26 14:11336054 1154:我算了一个值,花了200 ms 2019-03-26 14:11336054 1154:我做到了。336055 1155:我做了一件花了500ms的事2019-03-26 14:11336055 1155:我做了一件花了1000ms的事2019-03-26 14336011336055 1155:最终结果是12032019-。

AsyncMethod500ms()依赖于AsyncMethod1()的返回结果作为参数,所以我们可以以异步方式直接运行三个方法:AsyncMethod1()、AsyncMethod200ms()和AsyncMethod1000ms()。这时候三个方法都会设置异步子线程来执行,但是如果下面的AsyncMethod500ms()想要执行,就必须有asynccmethod 1()的返回值,所以这时候等待asynccmethod 1(),200ms之后,asynccmethod 1()的执行就完成了。M1。Wait()等待结束,继续执行AsyncMethod500ms(),并传入返回值m1。AsyncMethod1()的结果。最后,由于这四个方法的返回值需要累加,另外三个方法必须在此之前执行,所以需要单独执行asyncmodometrymans()。AsyncMethod200ms(),AsyncMethod1000ms()等等,因为此刻所有方法都是异步执行的,所以程序的执行时间会执行时间最长的方法的执行时间(AsyncMethod1000ms()执行1000ms,最长执行时间 1000ms)。

看完上面的内容,我们可以肯定,在某些情况下,异步编程可以大大提高我们程序运行的效率,但是大家之所以提倡使用异步编程,不仅仅是因为软件的原因,还有硬件的原因。

前段时间,我们把原来运行在办公电脑上的程序发布到一台搭载双E5的DELL blade机器上,发现在DELL blade机器上运行的性能比之前的办公电脑差。起初,我们怀疑戴尔刀片式服务器使用了虚拟机,这可能在某些地方设置不正确。后来经过一系列的服务器性能测试,无论是CPU处理速度、磁盘IO还是网络带宽,DELL blade机器都远远优于我们以前的办公电脑,但是我们运行的程序中有一个接口的效率却不如我们以前的办公电脑!

?(直到有一天以后,随着我对异步编程的理解的加深。NET Core,我终于明白为什么了。)

我们先来看看日常开发中使用的英特尔CPU和服务器中使用的CPU之间的对比

开发计算机中央处理器:英特尔酷睿i5 8500处理器

基本处理器频率:3GHz最大睿频频率:4.1GHz核心数:六核线程数:六线程服务器CPU:英特尔至强D-2177 NT处理器

处理器基本频率:1.90 GHz最大睿频频率:3.00 GHz核心数:14线程数:28从上面的对比可以发现,两者的区别是很明显的。i5处理器的基本频率和最大睿频都高于服务器使用的至强处理器,但核心和线程的数量远不如至强处理器。如果我们所有的程序都使用同步编程,以WebApi为例,每个请求中调用的方法只在CPU的某个核心/线程中执行。换句话说,CPU的单核频率直接影响同步方法的执行效率,而我们之前的程序几乎都采用了同步方法。办公电脑上的i5处理器和服务器使用的至强处理器单核频率的差异,显然是之前性能问题的直接原因。

鉴于服务器CPU的特点(单核频率低,核/线程数量多),在程序中使用异步/多线程模式是毋庸置疑的。

注意:

虽然异步编程在很多情况下可以提高程序的效率,但这并不意味着所有的方法都需要异步执行才能使用异步。如果同步执行的成本甚至低于创建异步线程的成本,那么这里绝对没有必要使用异步模式。至于取舍,可能需要一些经验来处理。

以上是我目前对中异步/多线程编程的理解。NET核心。希望对大家的学习有帮助,支持我们。

版权声明:在中使用异步编程的方法步骤 净核心是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。