Форум программистов, компьютерный форум, киберфорум
C++
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.67/6: Рейтинг темы: голосов - 6, средняя оценка - 4.67
0 / 0 / 0
Регистрация: 06.10.2020
Сообщений: 27
1

Как ускорить вычисления потоками?

12.03.2022, 13:05. Показов 1243. Ответов 7

Author24 — интернет-сервис помощи студентам
Подскажите, пожалуйста, как ускорить такой цикл с помощью потоков?

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/////
vector <double> lam,h;
//как-то заполняются
////////
double Cycle(vector<double> lam, vector<double> h, int N){
    vector<double> sumk;
    double summ(0);
    double sumi(0);
    for (int k = 0; k < N; k++) {
        for (int i = 0; i < N; i++) {
            sumi += lam[i] * h[abs(i - k)];
        }
        sumk.push_back(sumi);
        sumi = 0;
    }
    for (int m = 0; m < N; m++) {
        double sum(0);
        for (int k = 0; k < N; k++) {
            sum += h[abs(m - k)] * exp(-1 - sumk[k]);
        }
        summ += pow(y[m] - sum, 2);
    }
}
////

Пробовал вот так, но не работает

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/////
vector <double> lam,h;
//как-то заполняются
////////
double Cycle(vector<double> lam, vector<double> h, int N){
    vector<double> sumk;
    double summ(0);
    double sumi(0);
    for (int k = 0; k < N; k++) {
        auto f = [&sumi](int i, int k, vector<double> lam, vector<double> h) {
        sumi+=lam[i] * h[abs(i - k)];
            };
        for (int i = 0; i < N; i+=4) {
            thread one(f, i, k, lam, h);
            thread two(f, i+1, k, lam, h);
            thread three(f, i+2, k, lam, h);
            thread four(f, i+3, k, lam, h);
 
            one.join();
            two.join();
            three.join();
            four.join();
 
        }
        sumk.push_back(sumi);
        sumi = 0;
    }
    for (int m = 0; m < N; m++) {
        double sum(0);
        for (int k = 0; k < N; k++) {
            sum += h[abs(m - k)] * exp(-1 - sumk[k]);
        }
        summ += pow(y[m] - sum, 2);
    }
}
////
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
12.03.2022, 13:05
Ответы с готовыми решениями:

Как ускорить вычисления/дать больше ресурсов скомпилированному приложению в Borland C++ Builder
Уважаемые форумчане, В своей научной работе еще давно начал использовать Borland C++ Builder 6....

Надо ускорить алгоритм вычисления чисел с не повторяющимися цифрами
Помогите ускорить алгоритм. Надо определить все числа с не повторяющимися цифрами от 0 до...

Как ускорить вычисления
Добрый вечер. Прошу помочь с решением следующей задачи. В моей проге базовый модуль производит...

Как ускорить вычисления
Добрый день, у меня есть алгоритм (имеющий достаточно много вычислений). Его надо прогнать 10^9...

Как ускорить программные вычисления?
Паскаль использует только 1% памяти при сложных мат.вычислениях,и порой,это занимает часы. Можно ли...

7
Нарушитель
499 / 656 / 85
Регистрация: 23.11.2021
Сообщений: 3,621
Записей в блоге: 6
12.03.2022, 14:29 2
Самый простой вариант - прикрутить openmp.
0
0 / 0 / 0
Регистрация: 06.10.2020
Сообщений: 27
12.03.2022, 15:28  [ТС] 3
Посмотрел, но так и не понял, как openmp для цикла добавить. Можете помочь?
0
фрилансер
5498 / 5094 / 1047
Регистрация: 11.10.2019
Сообщений: 13,341
12.03.2022, 15:33 4
Цитата Сообщение от Nikis0715 Посмотреть сообщение
double sumi(0);
нужно синхронизировать доступ. Но это всё равно не добавит скорости. Вообще-то, нужно в каждом вызове лямбды считать свою переменную (без синхронизации), а потом всё это суммировать

Цитата Сообщение от Nikis0715 Посмотреть сообщение
auto f = [&sumi](int i, int k, vector<double> lam, vector<double> h)
векторы лучше захватить по ссылкам в лямбду, чем каждый раз передавать по значению в каждый поток
0
Нарушитель
499 / 656 / 85
Регистрация: 23.11.2021
Сообщений: 3,621
Записей в блоге: 6
12.03.2022, 15:38 5
В смысле "не понял"? Что непонятного в #pragma omp parallel for, которое нужно перед циклом добавить? Ну и собирать с ключом -fopenmp.
Вот так, например, можно считать гистограмму параллельно.
Почитай уже документацию по openmp!
0
1487 / 1414 / 240
Регистрация: 19.02.2010
Сообщений: 3,915
12.03.2022, 17:25 6
Лучший ответ Сообщение было отмечено Nikis0715 как решение

Решение

Цитата Сообщение от Nikis0715 Посмотреть сообщение
как ускорить такой цикл
А тормозят там не циклы - там долго считается exp() внутри второго сдвоенного цикла.
Просто померь-сравни время работы первого сдвоенного и второго сдвоенного циклов - и увидишь, что любое ускорение первого сдвоенного мало уменьшит общее суммарное время.
0
0 / 0 / 0
Регистрация: 06.10.2020
Сообщений: 27
12.03.2022, 17:30  [ТС] 7
Понял, спасибо. Значит, буду думать, как быстрее экспоненту посчитать
0
2848 / 1997 / 986
Регистрация: 21.12.2010
Сообщений: 3,705
Записей в блоге: 10
13.03.2022, 11:03 8
1). в вектор sumk лучше записывать не sumi а уже готовую степень, количество вычислений степеней экспонент O(N^2) падает до O(N)
C++
1
sumk.push_back(exp(-1. - sumi));
2). Можно ещё и на потоки разбить - скорость вырастает ещё почти в (число ядер) раз: для N=70000 время падает с 8с до 2.6с (4 ядра)
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <ctime>
#include <future>
#include <thread>
using namespace std;
 
 
int main()
{
    int N = 70000;
    vector<double> lam(N, 1.), h(N, 1.), y(N, 1.);
    vector<double> sumk;
    sumk.reserve(N);
    double summ{}, sumi{}, sum{};
    int hc = std::thread::hardware_concurrency();
    std::vector<std::future<std::vector<double>>> vv;
    vv.reserve(hc);
    auto t1 = clock();
    auto lmd1 = [N, &lam, &h](int a, int b)
    {
        vector<double> sumk;
        sumk.reserve(b - a);
        double sumi{};
        for (int k = a; k < b; ++k)
        {
            for (int i = 0; i < N; ++i)
            {
                sumi += lam[i] * h[abs(i - k)];
            }
            sumk.push_back(exp(-1. - sumi));
            sumi = 0.;
        }
        return sumk;
    };
    for (int i = 0; i < hc; ++i)
    {
        int a = i * (N / hc);
        int b = (i + 1) * (N / hc) + ((i == hc - 1) ? N % hc : 0);
        vv.emplace_back(std::async(std::launch::async, lmd1, a, b));
    }
    for (auto& f : vv)
    {
        auto sf = f.share();
        sumk.insert(sumk.end(), sf.get().begin(), sf.get().end());
    }
 
    std::vector<std::future<double>> vf;
    vf.reserve(hc);
    auto t2 = clock();
    auto lmd2 = [N, &h, &sumk, &y](int a, int b)
    {
        double sum = 0., summcur = 0.;
        for (int m = a; m < b; ++m)
        {
            sum = 0.;
            for (int k = 0; k < N; ++k)
            {
                sum += h[abs(m - k)] * sumk[k];
            }
            summcur += pow(y[m] - sum, 2.);
        }
        return summcur;
    };
 
    for (int i = 0; i < hc; ++i)
    {
        int a = i * (N / hc);
        int b = (i + 1) * (N / hc) + ((i == hc - 1) ? N % hc : 0);
        vf.emplace_back(std::async(std::launch::async, lmd2, a, b));
    }
    for (auto& f : vf)
    {
        summ += f.get();
    }
 
    auto t3 = clock();
    std::cout << summ << "\n";
    std::cout << (t2 - t1) / 1000. << "\n";
    std::cout << (t3 - t2) / 1000. << "\n";
}
0
13.03.2022, 11:03
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
13.03.2022, 11:03
Помогаю со студенческими работами здесь

Ускорить вычисления с double (round и др.)
Здравствуйте, я пишу небольшую DLL на C++, но при большом объёме входных данных, она очень сильно...

Как ускорить
Задача Рассмотрим последовательность целых чисел длины N. По ней с шагом 1 двигается “окно” длины...

Как работать с потоками?
нужно создать 3 асинхронно работающих потока что есть сейчас: using System; using System.IO;...

Как работать с потоками?
Как создать поток? Как его стартануть? В какой он библиотеке? И вообще, как он называется? Когда...

Как ускорить циклы?
Здравствуйте, уважаемые. Так уж получилось, что мне нужно обработать несколько массивов данных,...

Как ускорить программу?
Задача: найти в строке такую подстроку максимальной длины, чтобы символы в ней не повторялись. ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
8
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru