zoukankan      html  css  js  c++  java
  • 第九节:深究并行编程Parallel类中的三大方法 (For、ForEach、Invoke)和几大编程模型(SPM、APM、EAP、TAP)

    一. 并行编程

    1. 区分串行编程和串行编程

      ①. 串行编程:所谓的串行编程就是单线程的作用下,按顺序执行。(典型代表for循环 下面例子从1-100按顺序执行)

      ②. 并行编程:充分利用多核cpu的优势,同时开启多个线程并行执行。(典型代表Parallel.For循环 下面例子从1-100无序执行)

     代码实践:

     1   {
     2                 //1. 串行 (从1-100按顺序执行)
     3                 for (int i = 1; i < 100; i++)
     4                 {
     5                     Console.WriteLine(i);
     6                 }
     7                 //2. 并行 (从1-100无序执行)
     8                 Parallel.For(1, 100, (item) =>
     9                 {
    10                     Console.WriteLine(item);
    11                 });
    12  }

    结论:串行的代码按顺序依次输出,并行的代码无顺序输出。

    2. 深究Parallel类中的方法 (For方法、ForEach方法、Invoke方法 这三个方法都是用来开启线程的)

    (1). Invoke方法

      a. 该方法的作用就是用来同时开启多个线程的。

      b. 该方法有两个重载,主要涉及到两个参数,用来配置最大并行数(即线程数)和一个可变的Action委托数组(详见源码)。

    案例一: 开启五个不同的线程调用五个方法

    我们发现一个现象,主线程等着这五个子线程执行完毕后才执行,但是我们并没有写线程等待的代码,所以我们可以总结:

    ①:并行计算,开启多个线程后,不需要再开辟线程等待,直接是主线程完成后续操作。

    ②:而普通多线程执行后,需要单独再开辟一个线程等待,然后主线程在执行。

     代码实践:

    1                 {
    2                     Parallel.Invoke(() => this.TestThread("bct1")
    3                                  , () => this.TestThread("bct2")
    4                                  , () => this.TestThread("bct3")
    5                                  , () => this.TestThread("bct4")
    6                                  , () => this.TestThread("bct5")
    7                         );
    8                 }

    案例二: 指定最大并行数进行线程调用

    我们发现,五个任务中的四个任务同时由不同线程开启,当其中一个任务结束时,第五个任务开启,并由刚结束的任务的线程来执行。

                    {
                        //设置最大的线程并行数
                        ParallelOptions p = new ParallelOptions();
                        p.MaxDegreeOfParallelism = 4;
    
                        Parallel.Invoke(p, () => this.TestThread("bct1")
                                    , () => this.TestThread("bct2")
                                    , () => this.TestThread("bct3")
                                    , () => this.TestThread("bct4")
                                    , () => this.TestThread("bct5")
                           );
                    }

    (2). For方法 (前两个参数之间的差代表任务的个数)

      这里介绍一个简单重载: public static ParallelLoopResult For(int fromInclusive, int toExclusive, Action<int> body);

      fromInclusive:开始索引(含).

      toExclusive:结束索引(不含).

      body:将为每个迭代调用一次的委托.

    当然该方法中的其他重载中也有很丰富的功能,比如也可以配置最大线程数。

    代码实践:

     1  {
     2                 //案例一:前两个参数之间的差,就为并行计算线程的个数
     3                 {
     4                     Parallel.For(5, 10, t =>
     5                         {
     6                             //这里的t分别为:5,6,7,8,9 五个数
     7                             string name = string.Format("bct{0}", t);
     8                             this.TestThread(name);
     9                         });
    10                 }
    11                 //案例二: 配置最大并行数
    12                 //结果:同时最多5个线程执行,但是还是要执行9个任务,(6,7,8,9,10,11,12,13,14),后面四个任务等前面的执行完后,再执行
    13                 {
    14                     ParallelOptions po = new ParallelOptions()
    15                     {
    16                         MaxDegreeOfParallelism = 5    //表示最大线程数为5,后面即使配置超过5,也无效
    17                     };
    18                     Parallel.For(6, 15, po, (t, state) =>
    19                     {
    20                         string name = string.Format("bct{0}", t);
    21                         this.TestThread(name);
    22                         //state.Break();   //退出单次循环(没看到实际作用)
    23                         // state.Stop();     //退出全部循环(没看到实际作用)
    24                         //return;
    25                     });
    26                 }
    27             }

    (3). ForEach方法

      这里也是介绍一个简单的重载:int数组中的个数代表需要进行并行任务的个数,但并不一定所有任务同时执行,也不一定每个任务都是一个新线程执行。

    该方法当然也可以配置最大并行数。

     代码实践:

     {
                    //数组里的个数,就为并行进行并行任务数
                    Parallel.ForEach(new int[] { 3, 5, 44, 55, 100 }, t =>
                          {
                              //这里的t分别为:3, 5, 44, 55, 100五个数
                              string name = string.Format("bct{0}", t);
                              this.TestThread(name);
                         }
    }

    二. 常见的编程模型

    1.同步编程模型(SPM):单线线程、串行开发模式。

    2.异步编程模型(APM):xxxbegin、xxxend的模式。

    3.基于事件的编程模型(EAP): xxAsync这样的事件模式。 eg:WebClient。

    4.基于Task的编程模型(TAP): APM和EAP都可以使用Task来实现,微软的初衷就是想通过Task大一统异步编程领域。

    下面分享两段代码,不做深入研究了。

     1             {
     2                 FileStream fs = new FileStream(Environment.CurrentDirectory + "//1.txt", FileMode.Open);
     3                 var bytes = new byte[fs.Length];
     4                 var task = Task.Factory.FromAsync(fs.BeginRead, fs.EndRead, bytes, 0, bytes.Length, string.Empty);
     5 
     6                 var nums = task.Result;
     7 
     8                 Console.WriteLine(nums);
     9             }
    10             {
    11                 FileStream fs = new FileStream(Environment.CurrentDirectory + "//1.txt", FileMode.Open);
    12 
    13                 var bytes = new byte[fs.Length];
    14 
    15                 fs.BeginRead(bytes, 0, bytes.Length, (aysc) =>
    16                 {
    17                     var nums = fs.EndRead(aysc);
    18 
    19                     Console.WriteLine(nums);
    20 
    21                 }, string.Empty);
    22 
    23                 Console.Read();
    24             }

  • 相关阅读:
    window打开服务的dos命令
    struts(三) ---OGNL的学习和理解
    struts(二) ---中参数传值
    struts入门初步(一)
    javaSE之Object及hashcode等相关知识
    CSS小三角制作
    VM安装mac及dmg文件转换iso
    单例模式的学习与简单应用
    Tortoise 下修改服务器路径(Relocate与Switch)
    连接未关闭。 连接的当前状态为打开。问题的解决
  • 原文地址:https://www.cnblogs.com/yaopengfei/p/8279848.html
Copyright © 2011-2022 走看看