浅说C#异步和同步

2018-03-02 08:28:37来历:cnblogs.com作者:潇潇@暮雨人点击

共享

说到异步,那么与之对应的是什么呢?同步。那么C#的异步和同步是怎么作业的呢?

首要,咱们先来看看栗子:

新建一个控制台应用程序,在Program文件中增加如下:

 1  static void Main(string[] args) 2         { 3             //计时器 4             Stopwatch watch = new Stopwatch(); 5             //开端计时 6             watch.Start(); 7             Console.WriteLine($"{DateTime.Now.ToString()} 进入Main办法,履行线程:{System.Threading.Thread.CurrentThread.ManagedThreadId}"); 8             //调用使命一(同步) 9             TaskOne();10             // 调用使命二11             TaskTwo();12             //中止计时13             watch.Stop();14             Console.WriteLine($"{DateTime.Now.ToString()} 退出Main办法,履行线程:{System.Threading.Thread.CurrentThread.ManagedThreadId}");15             Console.WriteLine($"主线程总耗时:{watch.ElapsedMilliseconds}ms");16             Console.ReadKey();17         }18         19         /// <summary>20         /// 使命一21         /// </summary>22         static void TaskOne()23         {24             Console.WriteLine($"{DateTime.Now.ToString()} 进入TaskOne办法,履行线程:{System.Threading.Thread.CurrentThread.ManagedThreadId}");25             for (int i = 0; i < 5; i++)26             {27                 Console.WriteLine($"{DateTime.Now.ToString()} TaskOne正在履行,履行线程:{System.Threading.Thread.CurrentThread.ManagedThreadId}");28                 System.Threading.Thread.Sleep(1000);29             }30             Console.WriteLine($"{DateTime.Now.ToString()} 退出TaskOne办法,履行线程:{System.Threading.Thread.CurrentThread.ManagedThreadId}");31         }32         /// <summary>33         /// 使命二34         /// </summary>35         static void TaskTwo(){36             Console.WriteLine($"{DateTime.Now.ToString()} 进入TaskTwo办法,履行线程:{System.Threading.Thread.CurrentThread.ManagedThreadId}");37             for (int i = 0; i < 2; i++)38             {39                 Console.WriteLine($"{DateTime.Now.ToString()} TaskTwo正在履行,履行线程:{System.Threading.Thread.CurrentThread.ManagedThreadId}");40                 System.Threading.Thread.Sleep(1000);41             }42             Console.WriteLine($"{DateTime.Now.ToString()} 退出TaskTwo办法,履行线程:{System.Threading.Thread.CurrentThread.ManagedThreadId}");43         }

这个栗子很简单,界说了两个办法:TaskOne,TaskTwo。在里边每隔一秒输出一次当时时刻,和当时线程。TaskOne循环5次和TaskOne2次。然后在MAIN函数里边次序调用,并记载MAIN函数履行的总耗时时刻。F5运转作用如图:

从图中能够看出,程序次序履行TaskOne之后,再履行TaskTwo。履行线程未改动。

下面咱们改改,用异步办法改写下TaskOne。说到异步,咱们脑海里随之显现的我想会是它吧。关键字async。当然与之成对呈现的await也不能少了。先看看改写后的:

 /// <summary>        /// 使命一(异步)        /// </summary>        /// <returns></returns>        static async Task<int> TaskOneAsync()        {            Console.WriteLine($"{DateTime.Now.ToString()} 进入TaskOneAsync办法,履行线程:{System.Threading.Thread.CurrentThread.ManagedThreadId}");            var t = Task<int>.Run(() =>            {                var total = 0;                for (int i = 0; i < 5; i++)                {                    total++;                    Console.WriteLine($"{DateTime.Now.ToString()} TaskOneAsync正在履行,履行线程:{System.Threading.Thread.CurrentThread.ManagedThreadId}");                    System.Threading.Thread.Sleep(1000);                }                return total;            });            Console.WriteLine($"{DateTime.Now.ToString()} 退出TaskOneAsync办法,履行线程:{System.Threading.Thread.CurrentThread.ManagedThreadId}");            return await t;        }

main函数改为调用异步办法

 static void Main(string[] args)        {            //计时器            Stopwatch watch = new Stopwatch();            //开端计时            watch.Start();            Console.WriteLine($"{DateTime.Now.ToString()} 进入Main办法,履行线程:{System.Threading.Thread.CurrentThread.ManagedThreadId}");            //调用使命一(同步)            //TaskOne();            //调用使命一(异步)            TaskOneAsync();            // 调用使命二            TaskTwo();            //中止计时            watch.Stop();            Console.WriteLine($"{DateTime.Now.ToString()} 退出Main办法,履行线程:{System.Threading.Thread.CurrentThread.ManagedThreadId}");            Console.WriteLine($"主线程总耗时:{watch.ElapsedMilliseconds}ms");            Console.ReadKey();        }

F5运转后作用:

咱们能够看到Main函数的履行时刻从7082ms变为了2404ms。时刻大大的缩短了。可是,在main现已结束后,TaskOneAsync仍然还在运转中....,而且TaskOneAsync的履行线程不是主线程9而是10!!

下面咱们来好好整理下程序的履行进程,看图便知:

能够看到当程序进入Main办法履行,进入TaskOneAsync后,线程ID仍然是9,当遇到Task履行使命创立,并运转。主线程并没有堵塞,而是独自开了一个新的线程10去履行TASK使命。主线程仍然次序履行,然后退出异步办法。进入到TaskTwo中履行结束,最终直到Main办法结束时,由于TaskOneAsync耗时较长,线程10仍然持续在履行Task。直到Task结束。其实体系,在Task使命Run的时分,现已新开了一个线程履行Task里边的使命,然后主线程持续履行TaskTwo,在TaskTwo履行这段期间,使命TaskOneAsync也在另一个线程一起j履行。可见,Task会新开一个线程履行命令,当时线程不会被堵塞,因而Main线程其实底子没有像同步办法相同履行最耗时的TaskOneAsync里边的Task,而是交给了别的一个线程履行,这便是主线程履行时刻,大大缩短的原因。因而,这种处理机制,关于用户体会,是比较友爱的。其实,在咱们开发中,常常见到以async结束的办法。最常见的应该是IO读取,写入,以及 http资源恳求相关类库办法。由于这些都是比较耗时的,一般耗时的作业,为了不影响主线程呼应,咱们一般都选用异步办法进行处理。

那么,当咱们主线程,需求获取Task使命回来成果时,主线程会堵塞线程等候其成果回来后,再持续履行下去。改下Main办法里边的,验证一下:

 如图,得以验证,主线程堵塞了线程,等候Task履行结束后,再持续履行。

概括总结,异步和同步,我是这样了解的:

同步:一段指令,在同一线程上,被次序履行,中心没有插队。就比如去电影院买票,有很多人(待履行的指令),可是只要一个窗口(一个线程,一般指主线程)。后边的人,只能等前面的人买了票,走了,才干前一步,他们的步骤是共同。所以,称之为同步。

异步:一段指令,在履行的时分,其间一些指令与指令之间,被履行的时刻点相同,可是操作其履行的线程不相同。两者存在一段时刻的并行现象。比如电影院看到排队买票的人越来越多,司理立刻又新组织了一个售票员开了一个新窗口(开新线程)售票,把本来排队的人(待履行的指令),转移了一部分到新的窗口持续排队买票。这样本来售票窗口(主线程)的作业使命以及时刻,则相应减少了。

异步办法其实是一种处理机制,它有优点,也有坏处。假如咱们无端的乱用,会起反作用。由于,新开线程会耗费线程资源。所以,秉承一个准则:在不影响主线程呼应前提下,能不必则不必。

以上都是个人见解,如有过错,还望指出,望不吝赐教~~

相关文章

    无相关信息

微信扫一扫

明升m88.com微信大众渠道