Как эффективно использовать std :: async для выполнения операций с массивом указателей - PullRequest
0 голосов
/ 09 мая 2018

Я очень плохо знаком с современной библиотекой 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 голосов
/ 09 мая 2018

Проблема с асинхронными вызовами состоит в том, что они не выполняются в некотором юниверсе, где бесконечное количество задач может быть выполнено в одно и то же время.

Асинхронные вызовы выполняются на процессоре, который имеет определенное количество процессоров / ядер, и асинхронные вызовы должны быть выстроены в очередь для выполнения на них.

Теперь вот где возникают проблемы синхронизации, а также проблемы блокировки, голодания и других многопоточных проблем.

Вашему алгоритму очень трудно следовать, так как он порождает задачи внутри уже созданных задач. Что-то происходит, но за этим трудно следить.

Я бы решил эту проблему:

  1. Создание вектора результатов (который будет из асинхронных потоков)
  2. В цикле выполнить асинхронные вызовы (присваивая результат вектору)
  3. Затем переберите вектор reuslts, собирая результаты
0 голосов
/ 09 мая 2018

Основная проблема в том, что ваш код хочет запускать больше, чем размер массива / 100 потоков. Это означает, что более 100 потоков. 100 потоков ничего хорошего не сделают; они побеждают Смотрите std::thread::hardware_concurrency и вообще не используйте raw async или thread в производственных приложениях; написать пулы задач и соединить вместе фьючерсы и тому подобное.

Такое количество потоков является крайне неэффективным и может исчерпать системные ресурсы.

Вторая проблема заключается в том, что вам не удалось вычислить среднее значение для 2 значений.

Среднее begIdx и endIdx - это не endIdx/2, а скорее:

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

Живой пример .

Вы заметите, что я обнаружил проблему с вашей программой, добавив промежуточный вывод. В частности, он распечатал диапазоны, над которыми работал, и заметил, что он повторяет диапазоны. Это известно как «отладка printf» и является довольно мощным, особенно когда пошаговая отладка отсутствует (при таком количестве потоков переход по коду будет ошеломляющим)

...