Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.67/6: Рейтинг темы: голосов - 6, средняя оценка - 4.67
супер тупой
6 / 6 / 3
Регистрация: 29.08.2014
Сообщений: 90
Завершенные тесты: 1
1

Многопоточная версия программы работает медленнее однопоточной

17.06.2016, 01:50. Просмотров 1108. Ответов 13
Метки нет (Все метки)

Доброго времени суток! Возник довольно странный вопрос, запускаю примерно такую конструкцию:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
    auto l = []() {
        int a = 5, b = 1, c;
        c = a * b;
    };
 
    do {
        std::thread calc_thread1(l);
        std::thread calc_thread2(l);
 
 
        if (calc_thread1.joinable()) calc_thread1.join();
        if (calc_thread2.joinable()) calc_thread2.join();
    } while (1);
И все вроде бы работает. Но.
В VS, при выполнении программы, справа есть "средства диагностики". Там же показывается время выполнения программы. Вот это время у меня идет в разы медленнее, чем "реальное".
Причем программа в 2 потока выполняется раз в 25 медленнее, чем программа в 1 поток.
Собственно, где я повернул не туда?
0
QA
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
17.06.2016, 01:50
Ответы с готовыми решениями:

Многопоточная работа программы
К сожалению, не могу сам разобраться с многопоточкой, перепробовал множество путей - отсебятина,...

Многопоточная программа выполняется медленнее чем однопоточная
Программа должна создать один поток исполнения для каждого файла и использовать эти потоки для...

Система работает всё медленнее и медленнее (Ubuntu 14)
Ноут HP PAVILION dv6-6077er Core i7 2630QM 2000 Mhz 8GB DDR3 500Gb TOSHIBA MK5061GSYN ATI...

Оконная версия консольной программы работает некорректно
Попробовал переделать из консольного приложения под win forms, но возникло 2 проблемки 1)...

.NET программы работают медленнее?
Если любая скомпилированная .NET программа не является машинным кодом, а набором команд...

13
ASCII
97 / 70 / 12
Регистрация: 15.12.2013
Сообщений: 453
Завершенные тесты: 2
17.06.2016, 02:11 2
Цитата Сообщение от супер тупой Посмотреть сообщение
Собственно, где я повернул не туда?
Наверное везде
C++
1
2
3
4
5
6
7
8
do {
* * * * std::thread calc_thread1(l);
* * * * std::thread calc_thread2(l);
 
        if (calc_thread1.joinable()) calc_thread1.join();
* * * * if (calc_thread2.joinable()) calc_thread2.join();
 
} while (1);
Тут у Вас каждый цикл создает новый поток и каждый поток выполняет одно и тоже, тратится время на создание потоков, выделение памяти под их стек и т.д. и т.п.
Тут вообще нет никакого смысла создавать потоки.

Добавлено через 5 минут
Сам не супер знаток пока что по многопоточному программированию, но мне кажется, если вами движет чисто спортивный интерес, чтобы ускорить выполнение кода, попробуйте использовать пул потоков. То есть черный ящик, в котором уже созданы потоки и которые спят и ждут, пока им не передадут задачу для выполнения. Сам писал недавно такой, могу дать код.
Но там могут быть ошибки)
0
супер тупой
6 / 6 / 3
Регистрация: 29.08.2014
Сообщений: 90
Завершенные тесты: 1
17.06.2016, 02:16  [ТС] 3
ASCII, дело в том, что я привел примерный вид кода, который использую(в рабочем потоки, конечно, выполняют осмысленные вещи и цикл когда-нибудь заканчивается; да и смысл там от потоков - это в 2 раза ускорить вычисления). Вообще да, потоки использую для ускорения некоторых вычислений. Как-то недавно делал похожее, все работало правильно.
0
ASCII
97 / 70 / 12
Регистрация: 15.12.2013
Сообщений: 453
Завершенные тесты: 2
17.06.2016, 02:20 4
Цитата Сообщение от супер тупой Посмотреть сообщение
ASCII, дело в том, что я привел примерный вид кода, который использую(в рабочем потоки, конечно, выполняют осмысленные вещи и цикл когда-нибудь заканчивается; да и смысл там от потоков - это в 2 раза ускорить вычисления). Вообще да, потоки использую для ускорения некоторых вычислений. Как-то недавно делал похожее, все работало правильно.
Если код, который будут выполнять потоки и так выполняется сравнительно быстро, то у Вас будет только проигрыш в производительности.
Идею я Вам подал, сделайте так, чтобы потоки заранее были созданы, но спали, затем по сигналу, получали задачу, просыпались и выполняли ее.
0
17.06.2016, 02:20
супер тупой
6 / 6 / 3
Регистрация: 29.08.2014
Сообщений: 90
Завершенные тесты: 1
17.06.2016, 02:36  [ТС] 5
ASCII, ну это очевидно
Проблема то по сути не в этом, на фоне вычислений каждого из потоков, их создание не имеет значения. А в том, почему таймер VS показывает не то время?
Ну и раз так делать не хорошо(до чего я догадывался, но не знал как иначе), как это сделать
Цитата Сообщение от ASCII Посмотреть сообщение
сделайте так, чтобы потоки заранее были созданы, но спали, затем по сигналу, получали задачу, просыпались и выполняли ее
быстрый просмотр гугла не дал мне ответ.
0
ASCII
97 / 70 / 12
Регистрация: 15.12.2013
Сообщений: 453
Завершенные тесты: 2
17.06.2016, 02:52 6
Цитата Сообщение от супер тупой Посмотреть сообщение
быстрый просмотр гугла не дал мне ответ.
Так я же говорю, попробуйте пул потоков использовать
На самом деле, все от задачи зависит. Но вот я например изучая многопоточное программирование написал пул потоков.

https://github.com/ANDR-ASCII/thread-pool/blob/master/thread_pool.hpp

Суть такова: создаете в начале программы пул потоков, то есть объект класса, затем, когда хотите разделить вычисления, передаете пулу потоков задачи, как только вы их передаете, пул будит потоки, (которые создаются сразу и спят в ожидании задачи) и передает им задачу. Функция передачи задачи в пул, возвращает объект типа std::shared_future<T>, у которого есть функция get.

Вызывая эту функцию, поток, которые ее вызвал будет ожидать ее завершения, если задача еще исполняется, если уже выполнена, то просто вернется значение, которое вернула задача (функция, которую вы передаете пулу, называю задачей).

Добавлено через 6 минут
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
#include <iostream>
#include "thread_pool.hpp"
 
double func(double a, double b)
{
    return a + b;
}
 
int main()
{
    /* Потоки создаются здесь и завершаются при уничтожении объекта pool */
    black_box::thread_pool<double> pool;
 
    // каждый вызов функции передает функцию func в пул
    // что заставляет проснуться какие-то потоки и выполнить задачу
    auto result_1 = pool.add_task(func, 1.23, 3.14);
    auto result_2 = pool.add_task(func, 11.123, 123.456);
 
    /** 1 и 2 потоки выполняют по одной func */
 
    std::cout << "Result of first call: " << result_1.get() << std::endl;
    std::cout << "Result of second call: " << result_2.get() << std::endl;
 
    return 0;
}
По месту вызова get(), если потоки не завершились, код повиснет и будет ждать результата, как только поток доделает задачу, get вернет управление

Добавлено через 2 минуты
Но опять же, без конкретной задачи, вряд ли можно что-то дельного посоветовать. Да и схема распределения задач по потокам в пуле, не самая совершенная. Обнаруживает наименее загруженную очередь (по размеру задач в ней) и передает в эту очередь задачу.
У каждого потока своя очередь.
1
Valeryn
77 / 50 / 16
Регистрация: 17.05.2015
Сообщений: 264
17.06.2016, 08:38 7
может проблема в том, что время на вычисление у тебя уходит меньше, чем время на создание самих потоков?
0
супер тупой
6 / 6 / 3
Регистрация: 29.08.2014
Сообщений: 90
Завершенные тесты: 1
17.06.2016, 18:16  [ТС] 8
Хорошо, попробую пул потоков сделать.
Добавлю про задачу(раз никто не может абстрагироваться).
Есть массив:
C++
1
double u[N][N];//где N может быть и 128, и 256
Структура программы в общем такая:
C++
1
2
3
4
5
6
7
8
9
//расчеты некоторых формул
do {
   for(j=0..N){
      //опять расчеты некоторых формул
      for(i=0..N){
         //еще немного расчетов и заполнение массива u[i][j]
      }
   }
} while(пока не выполнится некоторое условие, которое зависит от расчетов в цикле);
Массив устроен так, что расчеты можно разделить на j=0..N/2 и j=N/2+1..N
Для этого и хочу использовать потоки.
Но я попрошу не отходить от проблемы, почему таймер VS идет не по реальному времени?
0
Excalibur921
828 / 512 / 90
Регистрация: 12.10.2013
Сообщений: 3,434
17.06.2016, 18:35 9
Интересно глянуть загрузку ядер если 1 поток и если 2…может эти потоки это абстракция и на их
инициализацию идет времени больше чем сам расчет.
А если сверить на практике без VS? Делаете в 1 поток расчет на 1 минуту, а в два?
0
супер тупой
6 / 6 / 3
Регистрация: 29.08.2014
Сообщений: 90
Завершенные тесты: 1
17.06.2016, 18:46  [ТС] 10
Excalibur921, те же средства VS показывают, что потоки реально грузят ЦП. На практике
Цитата Сообщение от супер тупой Посмотреть сообщение
программа в 2 потока выполняется раз в 25 медленнее, чем программа в 1 поток
0
Excalibur921
828 / 512 / 90
Регистрация: 12.10.2013
Сообщений: 3,434
17.06.2016, 18:55 11
Забудьте за VS. Засекаете время хоть на ручных часах и делаете прогу с выводом результата по окончании, глянуть загрузку ядер через диспетчер задач виндовс =).
1 потоковая будет 1 ядро а два потока будет 2 ядра нагружено или опять одно?
0
супер тупой
6 / 6 / 3
Регистрация: 29.08.2014
Сообщений: 90
Завершенные тесты: 1
17.06.2016, 19:04  [ТС] 12
Excalibur921, не уточнил, что смотрел через диспетчер на загрузку ЦП и замерял с помощью тайма. ну и несложно отличить 2сек от 50сек
0
ASCII
97 / 70 / 12
Регистрация: 15.12.2013
Сообщений: 453
Завершенные тесты: 2
18.06.2016, 06:35 13
Да бог вас знает, скажите, как мы можем помочь разобраться в проблеме производительности, если мы не видим ваш код? Откуда мы можем знать, что он у вас не так делает? Быть может вы с мьютексами переборщили, а может вы их вообще не используете? Может у вас данные поганятся из-за data race, а другой код как-то ожидает, поступления нормальных данных? Вот откуда нам знать то?
0
супер тупой
6 / 6 / 3
Регистрация: 29.08.2014
Сообщений: 90
Завершенные тесты: 1
18.06.2016, 12:45  [ТС] 14
ASCII, пожалуйста, код, который вызывает "фриз" таймера в VS:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
auto l = []() {
        int a = 5, b = 1, c;
        c = a * b;
    };
 
    do {
        std::thread calc_thread1(l);
        std::thread calc_thread2(l);
 
 
        if (calc_thread1.joinable()) calc_thread1.join();
        if (calc_thread2.joinable()) calc_thread2.join();
    } while (1);
Допустим, лямбда делает очень много вычислений(разных для каждого потока), что в этом коде ошибочно? В моем рабочем коде по сути такая же структура, никаких дата рейсов там быть не может, работа идет с раздельными данными.
0
18.06.2016, 12:45
Answers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
18.06.2016, 12:45

Работает медленнее, чем обычно
Всем привет! Написал приложение использующее OpenGL и WinAPI. Всё бы хорошо, если бы при тестах на...

Многопоточная реализация программы
Нужно сделать многопоточную реализацию этой программы: namespace Лабораторная_Работа__3 { ...

Код из-под COM работает в 3 раза медленнее
Всем доброго времени суток! Прошу уважаемых форумчан не пинать, если вопрос слишком простой, я...


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

Или воспользуйтесь поиском по форуму:
14
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Рейтинг@Mail.ru