• 异步编程,任务与并行编程,任务同步


    异步编程:

    同步:按照顺序,一件事情做完了才能接着做一件事情,比如主函数中执行多个顺序方法和语句,只有上一条语句或者方法执行完毕才能执行下一个方法或者语句。
    异步:开始一个任务(比如一个方法)后,让任务在另一个线程中执行,本线程可以继续执行别的事情,然后等待那个任务执行完毕

    比如一个UI按钮,UI就相当于一个主函数,而按钮事件就是调用的方法,如果使用同步,那么在方法执行期间,整个ui界面就会发生阻塞,从而导致无法做任何操作

    多线程和异步不是同一个概念,多线程是用于实现异步的一种方式。
    异步可以用线程来实现也可以不用线程实现,C#使用线程来实现

    传统方法一,异步模式,使用委托的BeginInvoke及EndInvoke

    class Program
        {
            public delegate int FooDelegate(string s);
    
            static void Main(string[] args)
            {
                Console.WriteLine("主线程" + Thread.CurrentThread.ManagedThreadId);
    
                FooDelegate fooDelegate = Foo;
                IAsyncResult result = fooDelegate.BeginInvoke("Hello World", null, null);
    
                Console.WriteLine("主线程继续执行做其他事...");
    
                int n = fooDelegate.EndInvoke(result);
                Console.WriteLine("回到主线程" + Thread.CurrentThread.ManagedThreadId);
                Console.WriteLine("结果是" + n);
                Console.ReadKey(true);
    
            }
    
            public static int Foo(string s)
            {
                Console.WriteLine("函数所在线程" + Thread.CurrentThread.ManagedThreadId);
                Console.WriteLine("异步线程开始执行:" + s);
                Thread.Sleep(1000);
                return s.Length;
            }
        }

    传统方法二,基于事件,对于完成后打印结果等后续语句,使用委托回调

    class Program_Callback
        {
            public delegate int FooDelegate(string s);
    
            static void Main(string[] args)
            {
                Console.WriteLine("主线程" + Thread.CurrentThread.ManagedThreadId);
    
                FooDelegate fooDelegate = Print;
                IAsyncResult result = fooDelegate.BeginInvoke("Hello World", PrintComplete, fooDelegate);//这里回调PrintComplete方法
                Console.WriteLine("主线程继续执行做其他事...");
                Console.ReadKey(true);
    
            }
    
            public static int Print(string s)
            {
                Console.WriteLine("函数所在线程" + Thread.CurrentThread.ManagedThreadId);
                Console.WriteLine("异步线程开始执行:" + s);
                Thread.Sleep(1000);
                return s.Length;
            }
    
            public static void PrintComplete(IAsyncResult result)
            {
                (result.AsyncState as FooDelegate).EndInvoke(result);
                Console.WriteLine("当前线程结束" + result.AsyncState.ToString());
            }
        }

    最新方式,基于任务,使用await和async关键字和Task类型

    await 表示等待任务执行,用来调用返回任务的方法,或者阻塞等待一个任务执行完毕
    async修饰一个方法,表示其中有await语句

    await task相当于EndInvoke()用于阻塞等待任务线程执行完毕

        class Program_awaitAndAsync
        {
            static async Task Main(string[] args)
            {
                Task<double> task = FacAsync(10);
    
                Console.WriteLine("主函数继续执行。。。");
                for (int i = 0; i < 10; i++) Console.WriteLine("main");
    
                double result = await task;//此处await对程序进行阻塞,直到task执行完毕 才会执行接下来的语句
    
                Console.WriteLine("结果为"+result);
                Console.ReadKey(true);
            }
    
            public static Task<double> FacAsync(int n)
            {
                //Run会开启一个新的线程来执行委托的程序
                return Task<double>.Run(() => {
                    double s = 1; for (int i = 1; i < n; i++) {
                        s = s + i;
                        Console.WriteLine("task");
                    }
                    return s;
                });
            }
    
            async void Test()
            {
                double result = await FacAsync(10);
                Console.WriteLine(result);
            }
        }

    任务与并行编程:

    并行任务库TPL(Task Parallel Library)
    最重要的是Task类和Parallel类。
    Task类,是利用线程池来进行任务的执行,比直接用ThreadPool更优化,更方便
    Parallel类,是 并行执行任务类的实用类,好处是可以隐式地包装使用Task,更方便

    多任务与多线程的关系,可以粗略的认为多任务的目标是充分使用多核cpu,而多线程却不一定,可能多线程使用的是同一个cpu,并且多任务的底层实现上使用到了多线程。

    使用Task.Run方法来得到Task实例

    Task<double> task=Task.Run(()=>SomeFun());
    double result=task.Result;//等待直到获得结果
    可以使用Task.WaitAll(task数组)等待所有task执行完毕
    可以使用task.ContinueWith(另一个task)来使得task一个一个执行

        class Program
        {
            static void Main(string[] args)
            {
                Task<double>[] tasks = {
                    Task.Run(()=>SomeFun()),
                    Task.Run(() => SomeFun())
                };
                Thread.Sleep(1);
                for(int i = 0; i < tasks.Length; i++)
                {
                    Console.WriteLine(tasks[i].Status);//状态
                    Console.WriteLine(tasks[i].Result);//获取结果,这里相当于wait,会等到任务结束
                }
    
                //Task.WaitAll(tasks);//等待所有任务结束
            }
    
           static double SomeFun()
            {
                return 1;
            }
        }

    Parallel类的使用:

    Parallel.Invoke(Action[] actions);并行执行多个任务,直到完成
    Parallel.For(0,100,i=>{...})
    Parallel.Foreach(list,Item=>{...})
    示例:并行计算矩阵乘法

    class Program_Parallel
        {
    
            //一般的矩阵相乘
            static void MultiMatrixNormal(double[,] matA, double[,] matB, double[,] result)
            {
                int m = matA.GetLength(0);
                int n = matA.GetLength(1);
                int t = matB.GetLength(1);
    
                for(int i = 0; i < m; i++)
                {
                    for(int j = 0; j < t; j++)
                    {
                        double temp = 0;
                        for(int k = 0; k < n; k++)
                        {
                            temp += matA[i, k] * matB[k, j];
                        }
                        result[i, j] = temp;
                    }
                }
            }
    
            //使用了多任务的矩阵相乘
            static void MultiMatrixParallel(double[,] matA, double[,] matB, double[,] result)
            {
                int m = matA.GetLength(0);
                int n = matA.GetLength(1);
                int t = matB.GetLength(1);
    
                Parallel.For(0, m, i =>
                  {
                      {
                          for (int j = 0; j < t; j++)
                          {
                              double temp = 0;
                              for (int k = 0; k < n; k++)
                              {
                                  temp += matA[i, k] * matB[k, j];
                              }
                              result[i, j] = temp;
                          }
                      }
                 });
                
            }
        }

    并行Linq(即PLinq)

    只要在集合上加上个.AsParallel()
    var a=(from n in persons.AsParallel() where n.Age>20&&n.Age<25 select n).ToList();

    下面是摘抄自https://blog.csdn.net/birdfly2015/article/details/105024216

    一、区别与联系
    从技术发展的时间线上,微软推出这几个的顺序是:Thread=>ThreadPool=>Task=>Parallel

    Thread
    优点在于提供了丰富的多线程操作API,缺点在于线程个数的使用不加限制,以及无法复用线程,因此推出了TheadPool技术
    ThreadPool
    优点在于解决了线程个数的限制以及线程的复用,缺点在于API较少而且线程等待问题解决起来较为麻烦,因此推出了Task技术
    Task
    优点在于丰富的API,以及多线程的方便管理,缺点在于线程数量控制较为麻烦,因此推出了Parrel技术
    Parallel
    优点在于丰富的API,多线程方便管理,线程数量控制简单,但是主线程也会参与计算,导致主线程的阻塞问题(但是这个问题可以通过包一层来解决)
    二、最佳实践
    1.通常绝大部分问题通过Task就能很好的解决
    2.最好不要使用线程嵌套线程
    3.注意访问公共资源需要加锁
    4.多线程参数的传递
    5.多线程完成时的判断

  • 相关阅读:
    hdu 1599 find the mincost route (最小环与floyd算法)
    hdu 3371(prim算法)
    hdu 1598 find the most comfortable road (并查集+枚举)
    hdu 1879 继续畅通工程 (并查集+最小生成树)
    hdu 1272 小希的迷宫(并查集+最小生成树+队列)
    UVA 156 Ananagrams ---map
    POJ 3597 Polygon Division (DP)
    poj 3735 Training little cats 矩阵快速幂+稀疏矩阵乘法优化
    poj 3734 Blocks 快速幂+费马小定理+组合数学
    CodeForces 407B Long Path (DP)
  • 原文地址:https://www.cnblogs.com/xiaoahui/p/12821436.html
Copyright © 2020-2023  润新知