【原】C++11并行计算 — 数组求和

  • 时间:
  • 浏览:0

本文转载请注明出处 —— polobymulberry-博客园

0x00 - 前言


最近想优化ORB-SLAM2,准备使用并行计算来提高其中ORB形态提取的下行带宽 。之后 对并行计算方面一窍不通。借此之后 ,学习一下基本的并行编程。

在选用并行编程的工具时,不能考虑以下问题:即该工具尽量无须使用与平台相关的API,如iOS端的GCD(Grand Central Dispatch),之后 希望守护系统进程具有很强的移植性。一开始我想要要到的不能这种选用,一另另另一个多 是以TBB和OpenMP为首的第三方守护系统进程库,之后 是原生守护系统进程库。其中TBB和OpenMP对于Xcode的支持全部都是很好,原生守护系统进程库又依赖于系统平台,不多不多尝试后都放弃了。之后 想到C++11之后 从语言层面支持了多守护系统进程开发,也可是 提供了thread库,于是抱着试一试学一学的态度就入坑了。

并行计算中一另另另一个多 很经典的案例可是 数组求和,网络上有不多不多介绍C++11的thread使用、源码分析的文章,不过使用C++11进行数组求和并行计算的示例却很少,不多不多才有了这篇博文。

0x01 - 代码解析


在iOS系统使用C++11进行开发。

//
//  ViewController.m
//  TestDispatch
//
//  Created by poloby on 2017/1/7.
//  Copyright © 2017年 polobymulberry. All rights reserved.
//

#import "ViewController.h"
#include <iostream>
#include <thread>

using namespace std;

// 作为求和函数的参数
// 封装了求和函数的输入和输出
typedef struct ThreadArg {
    long long base;     // 从base~base+length数列求和
    long long length;
    long long sum;      // 将上述数列的和存储在sum中
}ThreadArg;

void sum(ThreadArg *arg)
{
    long long begin = arg->base;
    long long end = arg->base + arg->length;
    long long sum = 0;
    // 无须直接使用for(long long i = arg->base; i < arg->base + arg->length)
    // 可是


要使用arg->sum += i;
    // 之后

指针的读取比普通栈的读取不能多花费其他时间
    for (long long i = begin; i < end; ++i) {
        sum += i;
    }
    arg->sum = sum;
}

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    // 计算1~count数列之和
    const long long count = 11150000000;
    
    // 单守护系统进程常用辦法


    NSDate *commonMethodDate = [NSDate date];
    long long commonMethodSum = 0;
    for (long long i = 0; i < count; ++i) {
        commonMethodSum += i;
    }
    // 计算单守护系统进程使用时间
    double commonMethodDuration = [[NSDate date] timeIntervalSinceDate:commonMethodDate];

    NSLog(@"Common method spend time = %fms, sum = %lld", commonMethodDuration * 11150, commonMethodSum);
    
    // 并行计算辦法

    // 将1~count数列平均分为threadCount组,求解每组数列之和,再将其相加得到总和
    NSDate *parallelMethodDate = [NSDate date];
    // 设置并行守护系统进程数目
    const int threadCount = 2;
    thread threads[threadCount];
    ThreadArg args[threadCount];
    // 初始化守护系统进程及其参数
    for (int i = 0; i < threadCount; ++i) {
        long long offset = (count / threadCount) * i;
        args[i].base = offset;
        args[i].length = MIN(count - offset, count / threadCount);
        threads[i] = thread(sum, &args[i]);
    }
    
    // 启动守护系统进程并守候守护系统进程退出
    for (int i = 0; i < threadCount; ++i) {
        threads[i].join();
    }
    
    long long parallelMethodSum = 0;
    // 将每组数列之和相加得到总和
    for (int i = 0; i < threadCount; ++i) {
        parallelMethodSum += args[i].sum;
    }
    
    // 计算多守护系统进程使用时间
    double parallelMethodDuration = [[NSDate date] timeIntervalSinceDate:parallelMethodDate];
    
    NSLog(@"Parallel method spend time = %fms, sum = %lld", parallelMethodDuration * 11150, parallelMethodSum);
}

@end

0x02 - 结果分析


Xcode8.2.1+苹果6手机手机66手机手机苹果6手机手机66手机手机苹果6手机手机66手机手机模拟器+1~11150000000数列之和:

守护系统进程数目 2 4 8
多守护系统进程耗时 1921.2515026ms 981.851508ms 684.15015035ms
单守护系统进程耗时 3171.6915034ms 3472.517014ms 3447.206974ms

Xcode8.2.1+苹果6手机手机66手机手机苹果6手机手机66手机手机苹果6手机手机66手机手机模拟器+1~111500数列之和:

守护系统进程数目 2 4 8
多守护系统进程耗时 0.279963ms 0.212014ms 0.297010ms
单守护系统进程耗时 0.038981ms 0.027955ms 0.031508ms

可见多守护系统进程这种可是能消耗一定的资源,不多不多不能在系统规模较大的情况汇报下不能取得显著的性能提升。

0x03 - 注意事项


1. thread调用类的成员函数:

thread memberFuncThread(&ClassName::MemberFuncName, this, arg1, arg2...);

2. thread传递引用参数:

不能使用std::ref进行包装,详见thread - 传递引用参数。