假如现在有一很长的字符串需要进行base16编码,如果使用单线程所耗费时间会很多,所以为了解决耗时的问题采用并行计算的方式来编码。
base16编码
将一个字节8位拆分成两个4位,四位表示最大值位0x0f,将拆分到的字节映射到0-f中。
基本原理:
1 | static const char base16[]="0123456789abcdef"; |
使用C++17提供的并行计算方法
C++17提供了for_each的方式来进行并行遍历,使用时需要包含execution头文件。
1 |
|
上述是使用foreach并行计算的简单案例,记录前后时间的差值作为运行时间。
给for_each的第一个参数设置位std::execution::par即可使用for_each来做并行计算,后面部分与一般for_each遍历无异。
中间使用lambda函数(也可以用仿函数)来处理编码,虽然可以并行计算提高效率,但由于函数调用依然会带来性能开销(可能会有多大百万次的调用,如果数据量够大的话)。
直接使用多线分块计算
直接使用Base16Encode作为子线程进行并行计算,并提供ThreadBase16Encode作为线程入口:
1 | void ThreadBase16Encode(const vector<unsigned char>& indata,vector<unsigned char>& outdata) |
threadnum获取计算机最大核心数,也即可使用的最大线程数
percount获取数据块的大小并用于计算地址的偏移量
随后对特殊情况进行处理,如果数据量小于线程数,则开一个线程进行计算
通过data()获取到indata和oudata的首地址作为参数传入子线程
随后声明线程数组开始进行分块计算:
- 获取每个线程分到数据块的地址偏移量
- 获取每块数据大小并对最后一块数据进行处理 <—可能会有分完块后的额外数据
- 传入参数并执行线程
总结
使用了两种方法进行并行计算:C++17的foreach和C++11的多线程,两者各有优点:
- 使用foreach可能会更方便一些,但会由于函数调用带来一些额外的性能开销,并且一些编译器可能不支持C++17
- 使用C++11的多线程计算会稍有麻烦,但好在只需要调用几次函数,在性能上会有不错的提升,尤其是数据量非常大的时候
- 本文作者: KongXinQing
- 本文链接: https://13114987559.github.io/2024/04/06/note/C++多线程入门:并行计算/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!