Nano Hash - криптовалюты, майнинг, программирование

Реализованы ли уже параллельные алгоритмы C ++ 17?

Я пытался поиграть с новыми функциями параллельной библиотеки, предложенными в стандарте C ++ 17, но не смог заставить его работать. Я пробовал компилировать с последними версиями g++ 8.1.1, clang++-6.0 и -std=c++17, но, похоже, ни одна из них не поддерживает #include <execution>, std::execution::par или что-то подобное.

При просмотре cppreference параллельных алгоритмов можно увидеть длинный список алгоритмов, утверждающих, что

В технической спецификации представлены распараллеленные версии следующих 69 алгоритмов из algorithm, numeric и memory: (... длинный список ...)

Похоже, алгоритмы готовы "на бумаге", но еще не готовы к использованию?

В этом вопросе SO более года назад В ответах утверждается, что эти функции еще не были реализованы. Но сейчас я ожидал увидеть какую-то реализацию. Есть ли что-нибудь, что мы уже можем использовать?



Ответы:


1

Вы можете направить https://en.cppreference.com/w/cpp/compiler_support на проверьте состояние реализации всех C++ функций. В вашем случае просто введите «Standardization of Parallelism TS», и вы обнаружите, что только компиляторы MSVC и Intel C++ поддерживают эту функцию.

16.11.2018
  • Я собрал репозиторий с открытым исходным кодом, который работает на компиляторах MSVC, Intel и g ++ 9.1, демонстрируя использование и производительность параллельной сортировки вместе с параллельной сортировкой слиянием (github.com/DragonSpit/ParallelAlgorithms) 18.10.2020

  • 2

    Они есть в GCC 9, но TBB необходимо установить отдельно

    В Ubuntu 19.10 все компоненты окончательно выровнены:

    • GCC 9 по умолчанию , и минимально необходимая версия для TBB
    • TBB (Intel Thread Building Blocks) находится на уровне 2019 ~ U8-1, поэтому он соответствует минимальным требованиям 2018 года.

    так что вы можете просто сделать:

    sudo apt install gcc libtbb-dev
    g++ -ggdb3 -O3 -std=c++17 -Wall -Wextra -pedantic -o main.out main.cpp -ltbb
    ./main.out
    

    и использовать как:

    #include <execution>
    #include <algorithm>
    
    std::sort(std::execution::par_unseq, input.begin(), input.end());
    

    см. также полный рабочий тест ниже.

    GCC 9 и TBB 2018 - первые, которые работают, как указано в примечаниях к выпуску: https://gcc.gnu.org/gcc-9/changes.html

    Параллельные алгоритмы и <execution> (требуется Thread Building Blocks 2018 или новее).

    Связанные темы:

    Установка Ubuntu 18.04

    Ubuntu 18.04 немного сложнее:

    Вот полностью автоматизированные протестированные команды для Ubuntu 18.04:

    # Install GCC 9
    sudo add-apt-repository ppa:ubuntu-toolchain-r/test
    sudo apt-get update
    sudo apt-get install gcc-9 g++-9
    
    # Compile libtbb from source.
    sudo apt-get build-dep libtbb-dev
    git clone https://github.com/intel/tbb
    cd tbb
    git checkout 2019_U9
    make -j `nproc`
    TBB="$(pwd)"
    TBB_RELEASE="${TBB}/build/linux_intel64_gcc_cc7.4.0_libc2.27_kernel4.15.0_release"
    
    # Use them to compile our test program.
    g++-9 -ggdb3 -O3 -std=c++17 -Wall -Wextra -pedantic -I "${TBB}/include" -L 
    "${TBB_RELEASE}" -Wl,-rpath,"${TBB_RELEASE}" -o main.out main.cpp -ltbb
    ./main.out
    

    Анализ тестовой программы

    Я тестировал эту программу, которая сравнивает скорость параллельной и последовательной сортировки.

    main.cpp

    #include <algorithm>
    #include <cassert>
    #include <chrono>
    #include <execution>
    #include <random>
    #include <iostream>
    #include <vector>
    
    int main(int argc, char **argv) {
        using clk = std::chrono::high_resolution_clock;
        decltype(clk::now()) start, end;
        std::vector<unsigned long long> input_parallel, input_serial;
        unsigned int seed;
        unsigned long long n;
    
        // CLI arguments;
        std::uniform_int_distribution<uint64_t> zero_ull_max(0);
        if (argc > 1) {
            n = std::strtoll(argv[1], NULL, 0);
        } else {
            n = 10;
        }
        if (argc > 2) {
            seed = std::stoi(argv[2]);
        } else {
            seed = std::random_device()();
        }
    
        std::mt19937 prng(seed);
        for (unsigned long long i = 0; i < n; ++i) {
            input_parallel.push_back(zero_ull_max(prng));
        }
        input_serial = input_parallel;
    
        // Sort and time parallel.
        start = clk::now();
        std::sort(std::execution::par_unseq, input_parallel.begin(), input_parallel.end());
        end = clk::now();
        std::cout << "parallel " << std::chrono::duration<float>(end - start).count() << " s" << std::endl;
    
        // Sort and time serial.
        start = clk::now();
        std::sort(std::execution::seq, input_serial.begin(), input_serial.end());
        end = clk::now();
        std::cout << "serial " << std::chrono::duration<float>(end - start).count() << " s" << std::endl;
    
        assert(input_parallel == input_serial);
    }
    

    На Ubuntu 19.10 ноутбук Lenovo ThinkPad P51 с процессором: процессор Intel Core i7-7820HQ (4 ядра / 8 потоков, база 2,90 ГГц, кэш 8 МБ), ОЗУ: 2x Samsung M471A2K43BB1-CRC (2x 16 ГБ, 2400 Мбит / с) типичный выход для входа со 100 миллионами номеров, которые нужно отсортировать:

    ./main.out 100000000
    

    был:

    parallel 2.00886 s
    serial 9.37583 s
    

    так что параллельная версия была примерно в 4,5 раза быстрее! См. Также: Что означают термины CPU связанный и связанный ввод-вывод означает?

    Мы можем подтвердить, что процесс порождает потоки с strace:

    strace -f -s999 -v ./main.out 100000000 |& grep -E 'clone'
    

    который показывает несколько строк типа:

    [pid 25774] clone(strace: Process 25788 attached
    [pid 25774] <... clone resumed> child_stack=0x7fd8c57f4fb0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7fd8c57f59d0, tls=0x7fd8c57f5700, child_tidptr=0x7fd8c57f59d0) = 25788
    

    Кроме того, если я закомментирую серийную версию и буду работать с:

    time ./main.out 100000000
    

    Я получил:

    real    0m5.135s
    user    0m17.824s
    sys     0m0.902s
    

    который еще раз подтверждает, что алгоритм был распараллелен с реального ‹пользователя и дает представление о том, насколько эффективно его можно распараллелить в моей системе (примерно в 3,5 раза для 8 ядер).

    Сообщения об ошибках

    Google, проиндексируйте это, пожалуйста.

    Если у вас не установлен tbb, возникает ошибка:

    In file included from /usr/include/c++/9/pstl/parallel_backend.h:14,
                     from /usr/include/c++/9/pstl/algorithm_impl.h:25,
                     from /usr/include/c++/9/pstl/glue_execution_defs.h:52,
                     from /usr/include/c++/9/execution:32,
                     from parallel_sort.cpp:4:
    /usr/include/c++/9/pstl/parallel_backend_tbb.h:19:10: fatal error: tbb/blocked_range.h: No such file or directory
       19 | #include <tbb/blocked_range.h>
          |          ^~~~~~~~~~~~~~~~~~~~~
    compilation terminated.
    

    Итак, мы видим, что <execution> зависит от неустановленного компонента TBB.

    Если TBB слишком старый, например по умолчанию Ubuntu 18.04, он не работает с:

    #error Intel(R) Threading Building Blocks 2018 is required; older versions are not supported.
    
    05.05.2019
  • Здесь указано: gcc.gnu.org/onlinedocs/gcc-9.1.0/libstdc++/manual/manual/: Примечание 3. Параллельные алгоритмы имеют внешнюю зависимость от Intel TBB 2018 или новее. Если заголовок <execution> включен, то -ltbb необходимо использовать для связи с TBB. Похоже, что параллельные алгоритмы реализуются Intel Parallel STL: github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B- v3 / include /, который сам требует TBB. 09.05.2019
  • @DanielLangr спасибо! Главный вопрос, который у меня возник (сейчас лень исследовать ;-)): является ли TBB в дереве, если да, мне нужно настроить сборку GCC с любыми дополнительными флагами, иначе как установить ее на Ubuntu. Я ничего не знал о -ltbb, так что это уже хорошее начало :-) Тогда я собираюсь протестировать что-нибудь и дать график здесь, это будет весело! 09.05.2019
  • Параллельные заголовки STL теперь являются частью libstdc ++. Они определяют параллельный бэкэнд и поддерживается только TBB. Внутренний заголовок TBB требуются заголовки TBB. Однако я не могу найти заголовки TBB как часть libstdc ++. Следовательно, это означает, что требуется не только связывание библиотеки TBB, но и предоставление заголовков TBB. Онлайн-демонстрация поддерживает это: wandbox.org/permlink/VSIcdvWCtTRko43Q. 09.05.2019
  • Кстати, я бы предпочел автономную реализацию параллельных алгоритмов STL, чем алгоритмы TBB. Я широко использую параллельную сортировку и провел множество экспериментов, которые в целом показали, что реализация параллельной быстрой сортировки и сортировки слиянием из libstdc ++ Parallel mode (PM) превосходит таковые из TBB. К сожалению, PM построен на OpenMP, и его повторная реализация потоками C ++ 11 совсем не тривиальна. 09.05.2019
  • @DanielLangr спасибо за эту информацию! Вы, должно быть, делаете там забавные вещи, хе-хе ;-) Я попробую поиграть с этим позже. Если у вас есть тестовый код с открытым исходным кодом, поделитесь ссылкой. 09.05.2019
  • @DanielsaysreinstateMonica Кстати, теперь я обнаружил, что в Ubuntu 19.10 все просто работает, и обновил ответ :-) 03.12.2019

  • 3

    Intel выпустила параллельную библиотеку STL, которая соответствует стандарту C ++ 17:

    Он объединяется с GCC.

    25.06.2018

    4

    Gcc еще не реализует Parallelism TS (см. https://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html#status.iso.2017)

    Однако libstdc ++ (с gcc) имеет экспериментальный режим для некоторых эквивалентных параллельных алгоритмов. См. https://gcc.gnu.org/onLineocs/libstdc++/manual/parallel_mode.html

    Заставляем его работать:

    Любое использование параллельных функций требует дополнительной поддержки компилятора и среды выполнения, в частности поддержки OpenMP. Добавить эту поддержку несложно: просто скомпилируйте приложение с флагом компилятора -fopenmp. Это свяжется с libgomp, библиотекой времени выполнения GNU Offloading and Multi Processing Runtime Library, присутствие которой обязательно.

    Пример кода

    #include <vector>
    #include <parallel/algorithm>
    
    int main()
    {
      std::vector<int> v(100);
    
      // ...
    
      // Explicitly force a call to parallel sort.
      __gnu_parallel::sort(v.begin(), v.end());
      return 0;
    }
    
    25.06.2018

    5

    Gcc теперь поддерживает заголовок выполнения, но не стандартную сборку clang из https://apt.llvm.org

    11.07.2021
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..