写点什么

深究并行编程 Parallel 类中的三大方法 (For、ForEach、Invoke)和几大编程模型 (SPM、APM、EAP、TAP)

作者:C++后台开发
  • 2022-11-17
    湖南
  • 本文字数:3072 字

    阅读完需:约 10 分钟

深究并行编程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                 }
复制代码



编辑切换为居中


添加图片注释,不超过 140 字(可选)


案例二: 指定最大并行数进行线程调用 我们发现,五个任务中的四个任务同时由不同线程开启,当其中一个任务结束时,第五个任务开启,并由刚结束的任务的线程来执行。


                {                    //设置最大的线程并行数                    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") ); }
复制代码



编辑切换为居中


添加图片注释,不超过 140 字(可选)


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


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


fromInclusive:开始索引(含).


toExclusive:结束索引(不含).


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


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

C/C++Linux服务器开发高级架构师/C++后台开发架构师免费学习地址

【文章福利】另外还整理一些C++后台开发架构师 相关学习资料,面试题,教学视频,以及学习路线图,免费分享有需要的可以点击领取


代码实践:


 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             }
复制代码


原文链接:第九节:深究并行编程 Parallel 类中的三大方法 (For、ForEach、Invoke)和几大编程模型(SPM、APM、EAP、TAP)

用户头像

C/C++后台开发技术交流qun:720209036 2022-05-06 加入

还未添加个人简介

评论

发布
暂无评论
深究并行编程Parallel类中的三大方法 (For、ForEach、Invoke)和几大编程模型(SPM、APM、EAP、TAP)_多线程_C++后台开发_InfoQ写作社区