C#基础知识学习——异步Task、Parallel 、 异步实例(十九)

异步定义

异步用途 通常用于执行完成时间较长的任务,比如:打开大文件、连接远程计算机、查询数据库等操作。应用程序调用方法异步执行某个操作时,应用程序可以在异步方法执行其任务时继续执行。
异步机制 异步编程采用future或callback机制,以避免产生不必要的线程。
异步核心 启动了的操作将在一段时间后完成, 这个操作正在执行时,不会阻塞原来的线程。启动了这个操作的线程可以继续执行其他任务,当操作完成时,会通知回调函数。
异步与同步异步与同步是相对于同步而言,跟多线程不能同一而论。同步执行是执行某个任务时,需要在该任务完成后才能继续执行另一个任务。异步执行在执行某个任务时,可以在该任务完成之前执行另一个任务。异步执行最重要的体现就是不排队,不阻塞。
单线程执行
在这里插入图片描述
多线程执行
在这里插入图片描述

异步与多线程

异步可以在单个线程上实现,也可以在多个线程上实现,还可以不需要线程(一些IO操作)。
只要存在多线程就存在异步,多线程就是异步的表现。

异步应用

.NET Framework的许多方面都支持异步编程功能:

  • 文件IO、流IO、套接字IO
  • 网络
  • 远程处理信道:HTTP、TCP和代理
  • 使用ASP.NET创建的XML WebServices
  • ASP.NET Web窗体
  • 使用MessageQuenue类的消息队列

.Net Framework为异步操作提供了两种设计模式

  • 使用IAsyncReault对象的异步操作
  • 使用事件的异步操作

Task

Task本身就表示一个异步操作,默认是运行在线程池里的线程,更轻量,可以更高效的利用线程:

  • 实现了控制任务执行的顺序
  • 实现父子任务
  • 实现任务的取消操作
  • 实现了进度报告
  • 实现了返回值
  • 实现了随时查看任务状态

Task启动与同步

Task.RunSynchronously

          //启用线程池中的线程异步执行
            Task t1 = Task.Factory.StartNew(() =>
            {
    
    
                Console.WriteLine("Task--1启动...");
            });
            //启用线程池中的线程异步执行
            Task t2 = Task.Run(() =>
            {
    
    
                Console.WriteLine("Task--2启动...");
            });

            Task t3 = new Task(() =>
            {
    
    
                Console.WriteLine("Task--3启动...");
            });
           // t3.Start();//启用线程池中的线程异步执行
            t3.RunSynchronously();//任务与主线程同步执行

Task.WaitAll

            Task t1 = Task.Run(() =>
            {
    
    
                Console.WriteLine("Task--1启动...");
            });
            Task t2 = Task.Run(() =>
            {
    
    
                Console.WriteLine("Task--2启动...");
            });

            //调用WaitAll() ,会阻塞调用线程,等待任务执行完成 ,这时异步也没有意义了          
            Task.WaitAll(new Task[] {
    
     t1, t2 });
            Console.WriteLine("Task完成...");

Task等待任务结果,处理结果

Task.ContinueWith

          Task t1 = Task.Run(() =>
            {
    
    
                Console.WriteLine("Task-1启动...");
            });
            Task t2 = Task.Run(() =>
            {
    
    
                Console.WriteLine("Task-2启动...");
            });
            //调用WaitAll() ,会阻塞调用线程,等待任务执行完成 ,这时异步也没有意义了          
            Task.WaitAll(new Task[] {
    
     t1, t2 });
            Console.WriteLine("Task完成...");

            //调用ContinueWith,等待任务完成,触发下一个任务,这个任务可当作任务完成时触发的回调函数。
            //为了获取结果,同时不阻塞调用线程,建议使用ContinueWith,在任务完成后,接着执行一个处理结果的任务。
            t1.ContinueWith((t) =>
            {
    
    
                Console.WriteLine("Task-1完成...");
            });
            t2.ContinueWith((t) =>
            {
    
    
                Console.WriteLine("Task-2完成...");
            });

Task.GetAwaiter().OnCompleted


            Task t1 = Task.Run(() =>
            {
    
    
                Console.WriteLine("Task-1启动...");
            });
            Task t2 = Task.Run(() =>
            {
    
    
                Console.WriteLine("Task-2启动...");
            });
            //调用WaitAll() ,会阻塞调用线程,等待任务执行完成 ,这时异步也没有意义了          
            Task.WaitAll(new Task[] {
    
     t1, t2 });
            Console.WriteLine("Task完成...");
             //调用GetAwaiter()方法,获取任务的等待者,调用OnCompleted事件,当任务完成时触发
            //调用OnCompleted事件也不会阻塞线程
            t1.GetAwaiter().OnCompleted(() =>
            {
    
    
                Console.WriteLine("Task-1完成...");
            });
            t2.GetAwaiter().OnCompleted(() =>
            {
    
    
                Console.WriteLine("Task-2完成...");
            });

Task任务取消

         //实例化一个取消实例
            var source = new CancellationTokenSource();
            var token = source.Token;

            Task t1 = Task.Run(() =>
            {
    
    
                Thread.Sleep(2000);
                //判断是否任务取消
                if (token.IsCancellationRequested)
                {
    
    
                    // 调用该方法后线程状态才会变为Canceled状态
                    token.ThrowIfCancellationRequested();
                    //Console.WriteLine("任务已取消");
                }
                Thread.Sleep(500);
                //token传递给任务
            }, token);

            Thread.Sleep(1000);
            Console.WriteLine(t1.Status);
            Thread.Sleep(1000);
            //取消该任务
            source.Cancel();
            Thread.Sleep(1000);
            Console.WriteLine(t1.Status);
            Console.ReadKey();

Task返回值

       public static void Test6()
        {
    
    
            Task<string> t1 = Task.Run(() => Tttst("HELLOW"));
            t1.Wait();//阻塞,等待结果
            Console.WriteLine(t1.Result);
        }
        static string Tttst(string STR)
        {
    
    
            return STR + "  FROM TEST";
        }

Async await

异步方法执行流程:
主线程调用MethodAsync方法,并等待方法执行结束
异步方法开始执行,输出“异步执行”
异步方法执行到await关键字,此时MethodAsync方法挂起,等待await表达式执行完毕,同时将控制权返回给调用方主线程,主线程继续执行。
执行Task.Delay方法,同时主线程继续执行之后的方法。
Task.Delay结束,await表达式结束,MehtodAsync执行await表达式之后的语句,输出“异步执行结束”。

       public static async void MethodAsync()
         {
    
    
            Console.WriteLine("异步执行");
            await Task.Delay(1000);
            Console.WriteLine("异步执行结束");
        }

在这里插入图片描述

Task.Delay与Thread.Sleep

Thread.Sleep会阻塞线程。而Task.Delay创建一个将在设置时间后执行的任务,就相当于一个定时器,多少时间后再执行操作,不会阻塞执行线程。

     public static async Task Test7Async()
        {
    
    
            Console.WriteLine("await执行前..." + Thread.CurrentThread.ManagedThreadId);
            await Task.Run(() =>
            {
    
    
                Console.WriteLine("await执行..." + Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(5000);
                Console.WriteLine("await执行结束..." + Thread.CurrentThread.ManagedThreadId);

            });
            Thread.Sleep(2000);
            Console.WriteLine("await之后执行..." + Thread.CurrentThread.ManagedThreadId);

        }

在这里插入图片描述

并行库Parallel类

该类位于System.Threading.Tasks名称空间中,提供了数据和任务并行性。

Parallel.Invoke

如果多个任务并行运行,可以使用Parallel.Invoke方法。该方法允许传递一个Action委托数组。

 /// <summary>
        /// 并行执行多个任务
        /// </summary>
        public static void ParalelDemo1()
        {
    
    
            // 通过Paralel类对象来并行执行3个任务
            Action task1 = () =>
            {
    
    
                for (int i = 0; i < 1000000; i++)
                {
    
    
                    Console.WriteLine($"1111111i=" + (i * 4));
                }
            };

            Action task2 = () =>
            {
    
    
                for (int i = 0; i < 1000000; i++)
                {
    
    
                    Console.WriteLine($"222222i=" + (i * 4));
                }
            };

            Action task3 = () =>
            {
    
    
                for (int i = 0; i < 1000000; i++)
                {
    
    
                    Console.WriteLine($"33333333i=" + (i * 4));
                }
            };

            // 并行执行
            Parallel.Invoke(task1, task2, task3);
        }

Parallel.For

Parallel.For()方法类似C#语法的for循环语句,多次执行一个任务。但该方法并行运行迭代,迭代的顺序没有定义。

Parallel.For()方法中,前两个参数定义了循环的开头和结束,第三个参数是一个Action委托。Parallel.For方法返回类型是ParallelLoopResult结构,它提供了循环是否结束的信息。

Parallel.For有多个重载版本和多个泛型重载版本。

/// <summary>
        /// 并行For循环
        /// </summary>
        public static void ParallelDemo2()
        {
    
    
            ParallelLoopResult plr = Parallel.For(0, 100, i =>
            {
    
    
                Console.WriteLine("{0},task:{1},thread:{2}", i, Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(5000);
            });
            if (plr.IsCompleted)
            {
    
    
                Console.WriteLine("completed!");
            }
         }

在这里插入图片描述

停止Parallel.For

 ParallelLoopResult plr = Parallel.For(0, 100, (int i, ParallelLoopState pls) =>
            {
    
    
                Console.WriteLine("{0},task:{1},thread:{2}", i, Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
                if (i > 5) pls.Break();
            });
            Console.WriteLine("is completed:{0}", plr.IsCompleted);
            Console.WriteLine("最低停止索引:{0}", plr.LowestBreakIteration);

Parallel.ForEach

Parallel.ForEach方法遍历实现了IEnumerable的集合,类似于foreach,但以异步方式遍历。没有确定遍历顺序。

  string[] data = {
    
    
                "zero",
                "one",
                "two",
                "three",
                "four",
                "five",
                "six",
                "seven",
                "eight",
                "nine",
                "ten",
                "eleven",
                "twelve"
            };

            ParallelLoopResult plr = Parallel.ForEach<string>(data, s =>
            {
    
    
                Console.WriteLine(s);
            });
            if (plr.IsCompleted)
                Console.WriteLine("completed!");

在这里插入图片描述

Task 异步实例

同步与异步区别

同步:

       public static   void LongProcess()
        {
    
    
            Console.WriteLine("LongProcess===>批量读取2000个点位数据");
            //模拟读取数据需要时间5秒
             Thread.Sleep(5000);//会阻塞线程
           
            Console.WriteLine("LongProcess===>批量读取数据结束。。。");
        }
        public static void ShortProcess()
        {
    
    
            Console.WriteLine("ShortProcess===>批量读取200个点位数据");
            //模拟读取数据需要时间5秒
            Thread.Sleep(5000);
            Console.WriteLine("ShortProcess===>批量读取数据结束。。。");
        }

在这里插入图片描述
异步:

       public static async void LongAsyncProcess()
        {
    
    
            Console.WriteLine("LongProcess===>Async批量读取2000个点位数据");
            //模拟读取数据需要时间5秒 
            await Task.Delay(5000);
            Console.WriteLine("LongProcess===>Async批量读取数据结束。。。");
        }
        public static void ShortProcess()
        {
    
    
            Console.WriteLine("ShortProcess===>批量读取200个点位数据");
            //模拟读取数据需要时间5秒
            Thread.Sleep(5000);
            Console.WriteLine("ShortProcess===>批量读取数据结束。。。");
        }

在这里插入图片描述

异步方法

不带返回值的异步方法

       public async static void TestTask()
        {
    
    
            await Task.Run(() => {
    
     });
        }
        public async static Task TestTask1()
        {
    
    
            await Task.Run(() => {
    
     });
        } 

带返回值的异步方法与调用方法

         /// <summary>
        /// 异步方法调用
        /// </summary>
        public static async void TestASYNC()
        {
    
    
            //方法一 异步执行
            Task<int> result = LongProcesss();
            var var2 = await result;
            方法二 阻塞当前线程
            var var2 = await LongProcesss1(); 
           
            Console.WriteLine($"Result:{
      
      var2}");
        }
        /// <summary>
        /// 带返回值的异步方法
        /// </summary>
        /// <returns></returns>
        public async static Task<int> LongProcesss()
        {
    
    
            Console.WriteLine("异步线程开始");
            await Task.Delay(5000);
            return 10;
        }

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_45496521/article/details/128798164