隐藏

C#异步多线程之TASK

发布:2019/10/15 22:33:51作者:管理员 来源:本站 浏览次数:980

简介

TASK首次引入.net Framework 4中,Task对象通常是以异步方式执行于线程池上,是基于ThreadPool的,您可以使用 Status 属性,以及 IsCanceled,IsCompleted和 IsFaulted 属性,以确定任务的状态,Task是目前最为推崇的多线程方法

Task的启动方式

                //常规启动

                Task.Run(() => DoSomeThing());

                //也可以用其构造函数启动

                new Task(() => DoSomeThing()).Start();

                //工厂方式启动

                Task.Factory.StartNew(() => DoSomeThing());

               以上几种启动方式没有什么优劣差别

waitAny waitAll

    #region waitAny waitAll

            {

                //动物界举办了第二届赛跑比赛,参赛的有兔子,乌龟,老虎,大象,长颈鹿

                Console.WriteLine("动物界举办了第二届赛跑比赛,参赛的有兔子,乌龟,老虎,大象,长颈鹿");

                List<Task> tasks = new List<Task>();

                tasks.Add(Task.Run(() => Race("兔子")));

                tasks.Add(Task.Run(() => Race("乌龟")));

                tasks.Add(Task.Run(() => Race("老虎")));

                tasks.Add(Task.Run(() => Race("大象")));

                tasks.Add(Task.Run(() => Race("长颈鹿")));

 

                Task.WaitAny(tasks.ToArray());//会阻塞当前线程,等待某一个任务完成,才进入下一行,会卡界面

                Console.WriteLine("第一名产生");

                Task.WaitAll(tasks.ToArray());//阻塞当前线程,等待任务全部完成,会卡界面

            }

            #endregion

 

 

  //赛跑

        public void Race(string animal)

        {

            Console.WriteLine($"{animal}赛号为{Thread.CurrentThread.ManagedThreadId.ToString("00")},已就位");

            long lResult = 0;

            for (int i = 0; i < 1000000000; i++)

            {

                lResult += i;

            }

            Console.WriteLine($"{animal}到达终点");

        }

 

运行结果如下图,那么恭喜乌龟了

值得一提的是 WaitAny, WaitAll也提供了超时等待的Api 如Task.WaitAll(tasks.ToArray(), 1000); 最多等待1s,超时就不等了,-1为无限等待

还有一点就是,WaitAny, WaitAll卡的是运行线程,如果在启动一个Task将WaitAny, WaitAll方法包裹起来,就不会卡界面了,像这样

Task.Run(()={

Task.WaitAny(tasks.ToArray());

})

 

WhenAny WhenAll

WhenAny和WhenAll与WaitAny和WaitAll最大的区别在与一个阻塞主线程,一个不阻塞主线程,那么在waitAny和WhenAll完成之后的动作应该怎么写呢

                Task.WhenAny(tasks.ToArray()).ContinueWith(t =>

                {

                    Console.WriteLine("第一名产生");

                });//不阻塞当前线程

                Task.WhenAll(tasks.ToArray()).ContinueWith(t =>

                {

                    Console.WriteLine("比赛结束");

                });//不阻塞当前线程

用到了ContinueWith来实现,效果如下图

好吧,再次恭喜乌龟先生又一次拿到了冠军

因为WhenAny,WhenAll 它的返回值是一个Task,所以当某些时候需要调整执行顺序时,将方法加入TaskList中,再用WaitAny,WaitAll即可

Delay

延迟,和Thread有点像,但不一样

下面是Thread 2秒钟

{

                Stopwatch stopwatch = new Stopwatch();

                stopwatch.Start();

                Thread.Sleep(2000);

                stopwatch.Stop();

                Console.WriteLine(stopwatch.ElapsedMilliseconds);

            }

运行结果:

下面是delay

  Stopwatch stopwatch = new Stopwatch();

                stopwatch.Start();

                Task.Delay(2000).ContinueWith(t =>

                {

                    stopwatch.Stop();

                    Console.WriteLine(stopwatch.ElapsedMilliseconds);

                });

运行结果:

通过这两次对比,不难看出,Thread会卡住当前线程,delay不卡线程,只是可以等待一些时间,再去完成一些事情

并行编程(Parallel) 

  Console.WriteLine($"---------开始Parallel编程,线程id{Thread.CurrentThread.ManagedThreadId.ToString("00")}---------");

            Parallel.Invoke(() => { Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString("00")); }

                   , () => { Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString("00")); }

                   , () => { Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString("00")); });

            Console.WriteLine($"---------结束Parallel编程{Thread.CurrentThread.ManagedThreadId.ToString("00")}---------");

通过结果我们发现主线程参与了计算,算是节约了一个线程吧

还有遍历方法如下

Parallel.For(0, 5, i => Race("兔子" + i.ToString()));

有for,肯定有foreach

Parallel.ForEach(new int[] { 1, 2, 3, 4, 5 }, i => Race("兔子" + i.ToString()));

Parallel还有一个重要方法是可以控制并发数量

ParallelOptions options = new ParallelOptions();

                options.MaxDegreeOfParallelism = 3;

                Parallel.For(0, 10, options, i => Race("兔子" + i.ToString()));

运行结果为:

通过运行结果,可以看到程序始终只有3个线程在跑

写完!荆轲刺秦王