如何有效地使用std :: async对指针数组执行操作

时间:2018-05-09 10:30:05

标签: c++ c++11 c++14 stdasync

我对现代C ++库很陌生,并试图学习如何使用std :: async在大指针数组上执行某些操作。我编写的示例代码在异步任务启动时崩溃。

示例代码:

#include <iostream>
#include <future>
#include <tuple>
#include <numeric>


#define maximum(a,b)            (((a) > (b)) ? (a) : (b))

class Foo {
    bool flag;

public:

    Foo(bool b) : flag(b) {}

    //******
    //
    //******
    std::tuple<long long, int> calc(int* a, int begIdx, int endIdx) {
        long sum = 0;
        int max = 0;

        if (!(*this).flag) {
            return std::make_tuple(sum, max);
        }

        if (endIdx - begIdx < 100)
        {
            for (int i = begIdx; i < endIdx; ++i)
            {
                sum += a[i];
                if (max < a[i])
                    max = a[i];
            }
            return std::make_tuple(sum, max);
        }

        int midIdx = endIdx / 2;
        auto handle = std::async(&Foo::calc, this, std::ref(a), midIdx, endIdx);
        auto resultTuple = calc(a, begIdx, midIdx);
        auto asyncTuple = handle.get();

        sum = std::get<0>(asyncTuple) +std::get<0>(resultTuple);
        max = maximum(std::get<1>(asyncTuple), std::get<1>(resultTuple));

        return std::make_tuple(sum, max);
    }

    //******
    //
    //******
    void call_calc(int*& a) {
        auto handle = std::async(&Foo::calc, this, std::ref(a), 0, 10000);
        auto resultTuple = handle.get();

        std::cout << "Sum = " << std::get<0>(resultTuple) << "  Maximum = " << std::get<1>(resultTuple) << std::endl;
    }
};

//******
//
//******
int main() {
    int* nums = new int[10000];
    for (int i = 0; i < 10000; ++i)
        nums[i] = rand() % 10000 + 1;

    Foo foo(true);
    foo.call_calc(nums);

    delete[] nums;
}

任何人都可以帮我确定它崩溃的原因吗? 有没有更好的方法将并行性应用于大指针数组上的操作?

2 个答案:

答案 0 :(得分:1)

根本问题是你的代码想要启动超过数组大小/ 100个线程。这意味着超过100个线程。 100个线程不会做任何好事;他们会捶打。请参阅std::thread::hardware_concurrency,通常不要在生产应用中使用原始asyncthread;写任务池并将期货等拼接在一起。

许多线程都非常低效并且可能耗尽系统资源。

第二个问题是你无法计算2个值的平均值。

begIdxendIdx的平均值不是endIdx/2,而是:

int midIdx = begIdx + (endIdx-begIdx) / 2;

Live example

您会注意到我通过添加中间输出发现了程序的问题。特别是,我打印出它正在处理的范围,我注意到它是重复范围。这被称为“printf调试”,并且功能非常强大,特别是当基于步骤的调试不是这种情况时(通过这么多线程,逐步执行代码会让人麻木)

答案 1 :(得分:1)

异步调用的问题在于,在某些可以完全同时执行无限任务的Universe中没有完成它们。

在具有一定数量处理器/核心的处理器上执行异步调用,并且必须排列异步调用以在其上执行。

现在,这里出现同步问题,阻塞,饥饿等问题以及其他多线程问题。

您的算法非常难以遵循,因为它在已创建的任务中生成任务。有些事情正在发生,但很难遵循。

我会通过以下方式解决这个问题:

  1. 创建结果向量(将来自异步线程)
  2. 在循环中执行异步调用(将结果分配给向量)
  3. 然后循环收集结果的重新收集载体