使用 Task

先了解什么是异步什么是同步;

一、同步方法

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            //Main中调用
            SyncMethod("一");
            SyncMethod("二");
            Console.WriteLine("--------主线程--------");
            Console.ReadLine();


        }
        public static void SyncMethod(string str)
        {
            Console.WriteLine($"--------同步方法{str}--------");
            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(200);
                Console.WriteLine($"同步:{i}");
            }
        }
    }
}

 二、异步方法

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            //异步方法
            //Main中调用
            AsyncMethod("一");
            AsyncMethod("二");
            Console.WriteLine("--------主线程--------");
            Console.ReadLine();

        }
        public static void AsyncMethod(string str)
        {
            Console.WriteLine($"--------异步方法{str}--------");
            Task.Run(() => {
                for (int i = 0; i < 10; i++)
                {
                    Thread.Sleep(200);
                    Console.WriteLine($"异步{str}:{i}");
                }
            });
        }
    }
}

三、Task开启线程的方法

 public static void TaskTest()
        {
            //【1】new Task().Start()
            Task task1 = new Task(() => { Console.WriteLine("Start开启一个子线程"); });
            task1.Start();
            //【1】实例化Task的一个重载,可传入委托需要用到的参数
            Task task1_1 = new Task((inStr) => { Console.WriteLine($"Start开启一个子线程,入参{inStr}"); }, "入参AAA");
            task1_1.Start();
            //通过AsyncState 获取创建子线程时委托传入的参数值
            string result = task1_1.AsyncState.ToString();
            Console.WriteLine($"输出委托的传入参数:{result}");

            //【2】Task.Run()
            Task task2 = Task.Run(() => { Console.WriteLine("Run开启一个子线程"); });
            //【2】Task.Run<TResult>表示一个可以返回值的异步操作
            Task<long> task2_1 = Task.Run<long>(() =>
            {
                return DoSomethingLongTime();
            });
            long rst = task2_1.Result;//获取子线程返回的值

            //【3】Task.Factory.StartNew
            Task task3 = Task.Factory.StartNew(() => { Console.WriteLine("Factory.StartNew开启一个子线程"); });
            //【3】Task.Factory.StartNew<TResult>
            Task<long> task3_1 = Task.Factory.StartNew<long>(() =>
            {
                return DoSomethingLongTime();
            });
            long rst2 = task3_1.Result;
            //另外还可以
            TaskFactory task3_2 = new TaskFactory();
            task3_2.StartNew(() => { Console.WriteLine("TaskFactory开启一个子线程"); });

            //【4】new Task().RunSynchronously()同步执行,上述三种均是异步
            Task task4 = new Task(() => { Console.WriteLine("Factory.StartNew开启一个子线程111"); });
            task4.RunSynchronously();
            Task task4_1 = new Task(() => { Console.WriteLine("Factory.StartNew开启一个子线程222"); });
            task4_1.RunSynchronously();
            Task task4_2 = new Task(() => { Console.WriteLine("Factory.StartNew开启一个子线程333"); });
            task4_2.RunSynchronously();
            Task task4_3 = new Task(() => { Console.WriteLine("Factory.StartNew开启一个子线程444"); });
            task4_3.RunSynchronously();
            //以上线程中的方法将会依次执行,不再异步执行

            //【4】new Task().RunSynchronously()同步执行且带返回值的Task,(就当没开子线程)
            Task<long> task4_4 = new Task<long>(() =>
            {
                return DoSomethingLongTime();
            });
            task4_4.RunSynchronously();
            long resul = task4_4.Result;


        }
        //耗时操作
        public static long DoSomethingLongTime()
        {
            long iResult = 0;
            for (int i = 0; i < 1_000_000_000; i++)
            {
                iResult += i;
            }
            return iResult;
        }

    }

四、Task线程等待

(1)task.Wait()

        static void Main(string[] args)
        {
            Console.WriteLine("----主线程--Start-----");
            TaskTest();
            Console.WriteLine("----主线程--End-----");
            Console.ReadLine();
        }

        public static void TaskTest()
        {
            Task task1 = new Task(()=> 
            {
                DoSomethingLongTime();
            });
            task1.Start();
            //【1】内部执行完方可往下执行
            task1.Wait();
            //【2】指定等待的毫秒数,到指定毫秒后,不管是否执行完,都往下执行,相当于说好我要卡你主线程多久
            task1.Wait(1000);
            //作用同【2】,不过使用TimeSpan可以指定时分秒等更多的单位,更加的灵活
            task1.Wait(TimeSpan.FromMilliseconds(1000));
        }
        //耗时任务
        public static void DoSomethingLongTime()
        {
            long iResult = 0;
            for (int i = 0; i < 1_000_000_000; i++)
            {
                iResult += i;
            }
            Console.WriteLine("耗时任务完成!");
            //return iResult;
        }

(2)Task.WaitAny()&Task.WaitAll()

        static void Main(string[] args)
        {
            Console.WriteLine("----主线程--Start-----");
            TaskTest();
            Console.WriteLine("----主线程--End-----");
            Console.ReadLine();
        }

        public static void TaskTest()
        {
            List<Task> taskList = new List<Task>();
            Task task1 = Task.Run(() => { GetAlarmInfo("站点1"); });
            Task task2 = Task.Run(() => { GetAlarmInfo("站点2"); });
            Task task3 = Task.Run(() => { GetAlarmInfo("站点3"); });
            taskList.Add(task1);
            taskList.Add(task2);
            taskList.Add(task3);
            //Task.WaitAny需要传入一个Task的数组
            Task.WaitAny(taskList.ToArray());
            Console.WriteLine("有报警点查询到报警信息,需要报警");
			
			//WaitAll等待所有的任务完成,才往后执行
            //Task.WaitAll(taskList.ToArray());
            //Console.WriteLine("所有报警点都查询到报警信息,紧急报警");

        }

        public static void GetAlarmInfo(string name)
        {
            Console.WriteLine($"Start--开始查询报警【{name}】的数据");
            DoSomethingLongTime();//模拟查询任务
            Console.WriteLine($"End--查询到报警【{name}】的数据");
        }

        public static void DoSomethingLongTime()
        {
            long iResult = 0;
            for (int i = 0; i < 1_000_000_000; i++)
            {
                iResult += i;
            }
        }

(3)Task.WhenAny()&Task.WhenAll()&ContinueWith()

        static void Main(string[] args)
        {
            Console.WriteLine("----主线程--Start-----");
            //TaskTest(1);
            TaskTest(2);
            Console.WriteLine("----主线程--End-----");
            Console.ReadLine();
        }

        public static void TaskTest(int flag)
        {
            List<Task> taskList = new List<Task>();
            TaskFactory factory = new TaskFactory();
            taskList.Add(factory.StartNew(() => { GetAlarmInfo("站点1"); }));
            taskList.Add(factory.StartNew(() => { GetAlarmInfo("站点2"); }));
            taskList.Add(factory.StartNew(() => { GetAlarmInfo("站点3"); }));
            if (flag == 1)
            {
                //当传入的多个线程中任意一个线程执行完成后,继续执行执行ContinueWith中的任务(不卡主线程,因为新开了一个线程)
                Task.WhenAny(taskList.ToArray()).ContinueWith((continuationAction) =>
                {
                    Console.WriteLine($"【{flag}】-开始紧急报警");
                    DoSomethingLongTime();
                    Console.WriteLine($"【{flag}】-紧急报警完毕");

                });
            }
            else
            {
                //当传入的多个线程都执行完成后,继续执行执行ContinueWith中的任务(不卡主线程,因为新开了一个线程)
                Task.WhenAll(taskList.ToArray()).ContinueWith((continuationAction) =>
                {
                    Console.WriteLine($"【{flag}】-开始紧急报警");
                    DoSomethingLongTime();
                    Console.WriteLine($"【{flag}】-紧急报警完毕");

                });
            }
        }

        public static void GetAlarmInfo(string name)
        {
            Console.WriteLine($"Start--开始查询报警【{name}】的数据");
            DoSomethingLongTime();//模拟查询任务
            Console.WriteLine($"End--查询到报警【{name}】的数据");
        }

        public static void DoSomethingLongTime()
        {
            long iResult = 0;
            for (int i = 0; i < 1_000_000_000; i++)
            {
                iResult += i;
            }
        }

(4)ContinueWhenAny()&ContinueWhenAll()

            if (flag == 1)
            {
                //当传入的多个线程中任意一个线程执行完成后,继续执行执行ContinueWith中的任务(不卡主线程,因为新开了一个线程)
                Task.Factory.ContinueWhenAny(taskList.ToArray(), ((continuationAction) =>
                 {
                     Console.WriteLine($"【{flag}】-开始紧急报警");
                     DoSomethingLongTime();
                     Console.WriteLine($"【{flag}】-紧急报警完毕");

                 }));
            }
            else
            {
                //当传入的多个线程都执行完成后,继续执行执行ContinueWith中的任务(不卡主线程,因为新开了一个线程)
                factory.ContinueWhenAll(taskList.ToArray(),((continuationAction) =>
                {
                    Console.WriteLine($"【{flag}】-开始紧急报警");
                    DoSomethingLongTime();
                    Console.WriteLine($"【{flag}】-紧急报警完毕");

                }));
            }

五、线程返回值

(1)主线程中获取返回值,会阻塞主线程

        private void TaskMethod1()
        {
            //这样子在主线程内获取返回值,会导致主线程阻塞
            Task<long> task2_1 = Task.Run<long>(() =>
            {
                return DoSomethingLongTime1();
            });
            long rst = task2_1.Result;//获取子线程返回的值
        }

(2)使用ContinueWith获取返回值,并做后续操作,不会阻塞线程,并且还可以连环使用返回值

        private void TaskMethod2()
        {
            //使用ContinueWith会另外开一个线程不会卡顿
            Task<long> task2_1 = Task.Run<long>(() =>
            {
                //Console.WriteLine(task2_1.Result.ToString());
                //第一个任务的返回值,是无法在自己内部直接获取的
                return DoSomethingLongTime1();
            });
            task2_1.ContinueWith(t =>
            {
                // 这里的 t 是一个带返回值的Task
                // 通过 t.Result 可以取出上一个任务的返回值,然后再行使用
                Console.WriteLine(t.Result.ToString());
                return 2 + t.Result;
            }).ContinueWith(s=> 
            {
                //这里没有return ,系统自动识别是没有返回值的Task
                Console.WriteLine(s.Result.ToString());
            }) ;
        }

(3)使用ContinueWhenAny和ContinueWhenAny获取返回值并作不同的操作,不会阻塞主线程

        private void TaskMethod3()
        {
            List<Task<long>> tasks = new List<Task<long>>();
            TaskFactory factory = new TaskFactory();
            tasks.Add(factory.StartNew<long>(() => { return DoSomethingLongTime2(1); }));
            tasks.Add(factory.StartNew<long>(() => { return DoSomethingLongTime2(2); }));
            tasks.Add(factory.StartNew<long>(() => { return DoSomethingLongTime2(3); }));
            tasks.Add(factory.StartNew<long>(() => { return DoSomethingLongTime2(4); }));
            //在使用ContinueWhenAny获取第一个返回的数据
            factory.ContinueWhenAny(tasks.ToArray(), (t) =>
             {
                 Console.WriteLine($"第一个返回的结果:{t.Result}");
             });
            //使用ContinueWhenAll执行完所有任务后,找出最大值,最小值和结算总和
            factory.ContinueWhenAll(tasks.ToArray(),(t)=> 
            {
                long sumNum = 0;
                long maxNum = t.Max(x => x.Result);
                Console.WriteLine($"返回的最大值:{maxNum}");
                long minNum = t.Min(x => x.Result);
                Console.WriteLine($"返回的最小值:{minNum}");
                long sum = t.Sum(x => x.Result);
                Console.WriteLine($"返回的总和方式1:{sum}");
                foreach (var item in t)
                {
                    sumNum += item.Result;
                };
                Console.WriteLine($"返回的总和方式2:{sumNum}");
            });
        }

        private long DoSomethingLongTime2(int id)
        {
            Console.WriteLine($"Start--耗时任务【{id}】开始");

            long iResult = 0;
            for (int i = 0; i < 1_000_000_000; i++)
            {
                iResult += i;
            }
            iResult += id;//这里只是为了后面对比大小使用
            Console.WriteLine($"End--耗时任务【{id}】结束");
            return iResult;
        }

(88条消息) C#多线程之Thread,ThreadPool,Task,Parallel_鲤籽鲲的博客-CSDN博客

猜你喜欢

转载自blog.csdn.net/h_ppap/article/details/128676905