LINUX.ORG.RU

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

 , , ,


1

5

Всем привет.

UPD2: добавлены реализации boost и OpenMP, почищен код, добавлены комменты в код, немного переформулировано ТЗ (суть не поменялась).

Признаюсь: первый опыт с многопоточной программой, так что прошу ногами сильно не бить.

Решил написать простую программу генерации простых чисел по методу вычеркивания. В развитии этой темы, написал 6 алгоритмов, 4 из которых многопоточные, близнецы, но используют std:thread (метод Initiate3), std:async (Initiate4), boost (Initiate5), OpenMP (Initiate6). Изначально ожидал, что многопоточные алгоритмы загрузят все ядра процессора на 100% и дадут увеличение скорости работы программы. Результаты удивили:
- Все реализации выполняются примерно за одно время (даже OpenMP).
- Многопоточные реализации не быстрее однопоточной, а иногда даже медленнее!!!
std:thread - грузит одно ядро на 100%
std:async - грузит два ядра, общая нагрузка не более 100% одного ядра.
boost - грузит одно ядро
OpenMP - грузит два ядра (суммарная нагрузка 200%), но при этом выполняется не быстрее (обогреватель воздуха помещения)!

Вопрос 1: почему Initiate3,4,5 не грузит все ядра на полную мощность?
Вопрос 2: почему Initiate6 (OpneMP) грузит все ядра, но пи этом не быстрее?
Вопрос 3: Как получить профит от многопоточности в данной конкретной задаче?

Для тех, кто решится помочь - заранее спасибо, и вот инфа в помощь:

Краткое представление алгоритма. Создается массив, элементы которого соответствует числам 3, 5, 7... (ведь четные числа не простые априори). Если соотв. число простое, то значение элемента массива 1, если не простое - 0 (для чистоты эксперимента специально заменил bool на unsigned char). Заполняет массив функция Initiate, в параметрах которой - максимальное число до которого искать. Initiate1 втупую проверяет каждое число, Initiate2 - при нахождении простого числа проходит массив вперед и убирает (помечает не-простыми) соотв. числа, Initiate3,4,5,6 - то же, но с многопоточностью. MarkNonPrime2 и MarkNonPrime3 - близнецы, но вторая предназначена для запуска в отдельном потоке. Остальное, думаю, будет понятно из кода.

Запускать так:

$ g++ -std=c++11 -lpthread -L/usr/lib -lboost_thread prime.cpp -fopenmp -O0 -o prime && time ./prime

Выбор реализации - в main() вызвать нужный метод InitiateX.

Длительность выполнения программы регулировать изменяя параметр InitiateX в main.

Собственно код (prime.cpp):

#include <iostream>
#include <iomanip>
#include <vector>

#include <thread>

#include <future>

#include <boost/thread/thread.hpp>

using namespace std;

// Maximum threads that could be spawned (except OpenMP)
#define MAX_THREAD 100

class CPrimeNumbers{
public:
  vector<unsigned char> numbers; // Array starts with 3 and has a step of 2: 3, 5, 7, 9 ...
  
  inline uint NumberToIndex(const uint number) {return (number-3)/2;}; // BUG: check whether number is < 3
  inline uint IndexToNumber(const uint index) {return index*2+3;};
  
  void MarkNonPrime2(const uint v,const uint max); // Single thread version: mark all N*v numbers (N - integer, N*v<=max) as non-prime
  static void MarkNonPrime3(CPrimeNumbers *sno, const uint v,const uint max); // Multithreading version: mark all N*v numbers (N - integer, N*v<=max) as non-prime
public:
  // Find all prime numbers - different realizations
  void Initiate1(const uint max=6); // Simple algorithm - checking each number
  void Initiate2(const uint max=6); // Marking-forward algorithm, single thread
  void Initiate3(const uint max=6); // Marking-forward algorithm, multithreading using C++11, std::thread
  void Initiate4(const uint max=6); // Marking-forward algorithm, multithreading using C++11, std::async
  void Initiate5(const uint max=6); // Marking-forward algorithm, multithreading using Boost
  void Initiate6(const uint max=6); // Marking-forward algorithm, multithreading using OpenMP
  
  void Print(); // Outhput prime numbers found
  bool IsPrime(uint number); // Check whether given number is prime
};

bool CPrimeNumbers::IsPrime(uint number)
{
  uint i;
  
  // BUG: check whether number is =0
  if (number<4)
    return true;
  
  if (number%2==0)
    return false;
  
  for (i=0;i<NumberToIndex(number);i++)
    if ( numbers[i]==1 && number%IndexToNumber(i) == 0 )
      return false;
    
  return true;
};

/*static*/ void CPrimeNumbers::MarkNonPrime3(CPrimeNumbers *sno, const uint v,const uint max)
{
  uint n;
  
  n=v*3;
  while (n<=max) {
    sno->numbers[sno->NumberToIndex(n)]=0;
    n+=v*2;
  }
};

void CPrimeNumbers::MarkNonPrime2(const uint v,const uint max)
{
  uint n;
  
  n=v*3;
  while (n<=max) {
    numbers[NumberToIndex(n)]=0;
    n+=v*2;
  }
};

void CPrimeNumbers::Initiate6(const uint max)
{
  uint head,i;
  
  numbers.assign(NumberToIndex(max)+1,1);
  
  for (head=3;head<=max;head+=2) {
    if ( numbers[NumberToIndex(head)]==1 ) { // Is prime/unchecked yet
      if (!IsPrime(head)) { // Is not prime
        numbers[NumberToIndex(head)]=0;
      }
      else{ // Is prime
        /*********** Multithreading using OpenMP ***********/
        #pragma omp parallel
        {
          MarkNonPrime3(this,head,max);
        }
      }
    }
  };
};

void CPrimeNumbers::Initiate5(const uint max)
{
  uint head,i;
  vector<boost::thread> threads;
  
  numbers.assign(NumberToIndex(max)+1,1);
  
  for (head=3;head<=max;head+=2) {
    if ( numbers[NumberToIndex(head)]==1 ) { // Is prime/unchecked yet
      if (!IsPrime(head)) { // Is not prime
        numbers[NumberToIndex(head)]=0;
      }
      else{ // Is prime
        /*********** Multithreading using Boost ***********/
        if ( threads.size()==MAX_THREAD) {
          threads[0].join();
          threads.erase(threads.begin());
        }
        threads.push_back( boost::thread(MarkNonPrime3,this,head,max) );
      }
    }
  };
  
  for (auto t=threads.begin();t!=threads.end();t++)
    t->join();
};

void CPrimeNumbers::Initiate4(const uint max)
{
  uint head,i;
  
  numbers.assign(NumberToIndex(max)+1,1);
  
  for (head=3;head<=max;head+=2) {
    if ( numbers[NumberToIndex(head)]==1 ) { // Is prime/unchecked yet
      if (!IsPrime(head)) { // Is not prime
        numbers[NumberToIndex(head)]=0;
      }
      else{ // Is prime
        /*********** multithreading using C++11, std::async ***********/
        async(launch::async,  MarkNonPrime3,this,head,max );
      }
    }
  };
};

void CPrimeNumbers::Initiate3(const uint max)
{
  uint head,i;
  vector<thread> threads;
  
  numbers.assign(NumberToIndex(max)+1,1);
  
  for (head=3;head<=max;head+=2) {
    if ( numbers[NumberToIndex(head)]==1 ) { // Is prime/unchecked yet
      if (!IsPrime(head)) { // Is not prime
        numbers[NumberToIndex(head)]=0;
      }
      else{ // Is prime
        /*********** Multithreading using C++11, std::thread ***********/
        if ( threads.size()==MAX_THREAD) {
          threads[0].join();
          threads.erase(threads.begin());
        }
        threads.push_back( thread(MarkNonPrime3,this,head,max) );
      }
    }
  };
  
  for (auto t=threads.begin();t!=threads.end();t++)
    t->join();
};

void CPrimeNumbers::Initiate2(const uint max)
{
  uint head,i;
  
  numbers.assign(NumberToIndex(max)+1,1);
  
  for (head=3;head<=max;head+=2) {
    if ( numbers[NumberToIndex(head)]==1 ) { // Is prime/unchecked yet
      if (!IsPrime(head)) { // Is not prime
        numbers[NumberToIndex(head)]=0;
      }
      else{ // Is prime
        /*********** Single thread ***********/
        MarkNonPrime2 (head,max);
      }
    }
  };
  
};

void CPrimeNumbers::Initiate1(const uint max)
{
  uint i;
  uint head;
  
  numbers.assign(NumberToIndex(max)+1,1);
  
  for (head=3;head<=max;head+=2) {
    if (! IsPrime(head) )
      numbers[NumberToIndex(head)]=0;
  };
  
};

void CPrimeNumbers::Print()
{
  uint n;
  
  n=3;
  for (auto i:numbers) {
    if (i) cout << n << " ";
    n+=2;
  }
  cout << endl;
}

int main()
{
  CPrimeNumbers s;
  
  /*********** Choose the algorithm ***********/
  s.Initiate1(100000);
  s.Print();
  
  return 0;
}

★★★★★

Насколько я понял у тебя там вообще потоки не запускаются. А проц загружается циклом в Initiate3.

Ида - код гавно.

ziemin ★★ ()
Ответ на: комментарий от ziemin

Насколько я понял у тебя там вообще потоки не запускаются.

Вот же:

threads.push_back( thread(MarkNonSimple3,*this,head,max) );

Kroz ★★★★★ ()

Код разбирать лень, попробуй больше потоков посоздавать, ну или с sched_setaffinity поиграться.

Ну и равномерную нагрузку точно тебе никто не гарантирует.

DarkEld3r ★★★★★ ()

Советую запустить в профайлере valgrind и посмотреть сколько времени IsSimple занимает.

quiet_readonly ★★★★ ()

зачем, мягко говоря, тебе нужны эти потоки? используй std::future & std::async.

nanoolinux ★★★★ ()

оформление кода ппц, нафиг столько макросов? Что за венгерская нотация в стиле начала девяностых? Пишите как принято в stl'е. И еще курить до просвещения.

http://habrahabr.ru/post/182610/

Gorthauer ★★★★★ ()

Предположу, что 1) твой код тратит больше времени на порождение ожидание потоков, чем может их породить; 2) просто напросто где-то ошибка (которую искать надо); 3) ну и так не пишут, советую ознакомиться с простыми приёмами при многозадачности.

Одна из больших проблем в твоём коде: постоянное порождение потоков - это очень затратно, запомни это :) Потому обычная практика состоит в том, чтобы запустить сначала все потоки, которые должны что-то делать, а потом давать им данные, а потом ждёшь завершения вычислений и останавливаешь потоки.

Ну а потоки грузят ядра, тупейший код:

void f() { while(true); }

...

for(int i = 0; i < 12; ++i){
    threads.push_back(std::thread(f));
}
threads[0].join();

invy ★★★★★ ()
Ответ на: комментарий от Gorthauer

Согласен на счет оформления, плохо читаемо. Чем не нравится венгерская нотация? Быстро к ней привыкаешь когда код по наследству приходит:) Еще бы поменять numbers -> m_numbers для красоты... Автор: Задай потокам маску ядер + поставь им FIFO максимального уровня.

Может я отстал от жизни, я boost для таких вещей использую, c++11 думаю еще не готов для повсеместного использования.

pulo ()
Ответ на: комментарий от Gorthauer

Что за венгерская нотация

Мусье точно знает, что такое венгерская нотация?

redgremlin ★★★★★ ()

Эх... и почему люди не ставят пробел перед { при просмотре кода подряд идущие ){ сливаются в один, гораздо проще увидеть открывающую скобку если стоит ) {

pulo ()

Простое число - это prime number.

anonymous ()
Ответ на: комментарий от quiet_readonly

Советую запустить в профайлере valgrind и посмотреть сколько времени IsSimple занимает.

Покопаю, спасибо.

Kroz ★★★★★ ()
Ответ на: комментарий от nanoolinux

зачем, мягко говоря, тебе нужны эти потоки? используй std::future & std::async.

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

Kroz ★★★★★ ()
Ответ на: комментарий от Gorthauer

оформление кода ппц, нафиг столько макросов?

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

И еще курить до просвещения. http://habrahabr.ru/post/182610/

Вот его и курил

Kroz ★★★★★ ()
Ответ на: комментарий от invy

Предположу, что 1) твой код тратит больше времени на порождение ожидание потоков, чем может их породить;

Да, мне тоже так показалось.

2) просто напросто где-то ошибка (которую искать надо);

Чем? Чем узнать время, которое затрачено на каждый поток?

3) ну и так не пишут, советую ознакомиться с простыми приёмами при многозадачности.
Что конкретно не так? Где почитать?

Одна из больших проблем в твоём коде: постоянное порождение потоков - это очень затратно, запомни это :) Потому обычная практика состоит в том, чтобы запустить сначала все потоки, которые должны что-то делать, а потом давать им данные, а потом ждёшь завершения вычислений и останавливаешь потоки.

Это было бы очень классно. Как это сделать? std::thread, как я понял, уже в конструкторе запускает поток. Если бы можно было приостанавливать, подбрасывать новые данные, а потом продолжать, вообще было бы идеально.

Kroz ★★★★★ ()

А как правильно дебаг делают? То же самое, только макросом? Типа DEBUG(«This is debug string»)?

actics ()

А как правильно дебаг делают? То же самое, только макросом? Типа DEBUG(«This is debug string»)?

actics ()
Ответ на: комментарий от actics

А как правильно дебаг делают? То же самое, только макросом? Типа DEBUG(«This is debug string»)?

Отлично! Только у тебя есть 10 функций, которые переплетаются в хаотичном калейдоскопе (соответствующему алгоритму программы), и каждая функция вываливает килограммы логов. Только вот, ты точно знаешь, что 9 функций работают так, как нужно, а сейчас ты работаешь над десятой. Тебе точно удобнее разгребать тонну логов ото всех функций, или, может, проще включить логи только для одной функции?

Вникни в то, что там написано.

Kroz ★★★★★ ()
Последнее исправление: Kroz (всего исправлений: 1)
Ответ на: комментарий от Kroz

Я таки спросил от ненания же. Ничего кроме #ifdef DEBUG я у тебя не вижу.

actics ()
Ответ на: комментарий от Kroz

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

если хочешь делать дебаг макросами, то делай лучше так:

#include <iostream>

#ifdef DEBUG
 #define DBGOUT(x) std::cout << x << "\n";
#else
 #define DBGOUT(x)
#endif /* DEBUG */

int main() {
 DBGOUT("test");
}
если компилируешь с -DDEBUG, вывод будет, если без - нет.

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

invy ★★★★★ ()
Последнее исправление: invy (всего исправлений: 1)
Ответ на: комментарий от invy

он ведь написал:

включения логирования для каждой конкретной функции

anonymous ()
Ответ на: комментарий от anonymous

Анон, ты бы хоть краем газа в код глянул, да? :)

invy ★★★★★ ()
Ответ на: комментарий от Kroz

Что конкретно не так? Где почитать?

Про механизмы синхронизации хотя бы: семафоры, мьютексы, мониторы, барьеры, ивенты, condition variables. Порешать простые задачки (или почитать как они решаются правильно): reader-writer, producer-consummer, dining philosophers, sleeping barber, про паттерн threadpool почитай.

Это было бы очень классно. Как это сделать? std::thread, как я понял, уже в конструкторе запускает поток. Если бы можно было приостанавливать, подбрасывать новые данные, а потом продолжать, вообще было бы идеально.

Например используя паттерн threadpool или по простому: У тебя есть очередь (fifo обычно) задач. Есть N потоков, следящих за очередью и как только в ней появляются новые задачи, один из потоков выбирает задачу из очереди и начинает её выполнять, по завершении, возвращается к отслеживанию очереди. И так далее.

Удобно, если операция для очереди queue.pop(); блокируюет исполнение (потока), пока в очереди нет ни одного элемента.

invy ★★★★★ ()
Ответ на: комментарий от invy

Анон, ты бы хоть краем газа в код глянул, да? :)

Анон все правильно написал. Рекомендую перечитать мой коммент: Мне всегда казалось, что несколько потоков должны грузить все ядра процессора... (комментарий)

P. S. И вообще оффтопик

Kroz ★★★★★ ()
Ответ на: комментарий от actics

Я таки спросил от ненания же. Ничего кроме #ifdef DEBUG я у тебя не вижу.

Правильно. Если раскомментировать #define DEBUG перед функцией, то эта функция (и только она) будет выводить логи (в данном случае с помощью cout, но иногда использую более сложные механизмы). В конце фцнкции #undef, чтобы эффект не распространялся на другие функции. Удобно.

Kroz ★★★★★ ()
Ответ на: комментарий от Kroz
#define DBGOUT(x) std::cout << __FILE__ << ":" << __LINE__ << ": " << __func__ << ": " << x << "\n";

и грепом потом

invy ★★★★★ ()
Ответ на: комментарий от invy

Использую практически тоже самое, только std::cerr, на всякий случай, вдруг упадет и не успеет вывести лог.

pulo ()
Ответ на: комментарий от pulo

На работе делаю так же примерно, конечно у меня не просто cout, а мой простенький велосипедо-класс, который может или в файл или в базу(правда я это пока никогда не использовал) писать.

invy ★★★★★ ()
Последнее исправление: invy (всего исправлений: 1)

мужик, с дебугами реально копец. код нечитаем.

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


//полупсевдокод
array[String] enableds = array("name1", "name2", "name3");

bool enabled(const char * fname) {
  return inArray(fname, enableds);
}

void debugMsg(const char * msg, const char * fname) {
  if(enabled(fname)) {
    cout<<fname<<" - "<<msg<<endl;
  }
}

AndreyKl ★★★★★ ()
Ответ на: комментарий от AndreyKl

из кода понял только что марк не прост даже дважды или трижды не прост.. , но это весьма вероятно от того что я сильно хочу спать и плохо соображаю что в совокупности с нечитаемостью твоих дебагов даёт такой вот эффект :)

чувак который предложил грепать рулит и педалит.

ну и тебе похоже уже разъяснили в чём была твоя проблема...

AndreyKl ★★★★★ ()
Ответ на: комментарий от invy

#define DBGOUT(x) std::cout << __FILE__ << ":" << __LINE__ << ": " << __func__ << ": " << x << «\n»;
и грепом потом

Хм. Тогда уже __PRETTY_FUNCTION__ , так как __func__ не показывает имя класса.

Но, если честно, все равно это сложнее. Сейчас у меня включение отладки выглядит так: «Навел курсор на строку #define DEBUG», Ctrl+Shift+D (раскомментировал), Alt+Tab (в консоль), Up (предыдущая комманда), Enter => profit. Если через grep, то сюда добавится «дописать '| grep ...'» или «стереть '| grep ...'» (в зависимости от того, нужен лог или не нужен), что дольше и сложнее.

Но за __func__ спасибо, раньше знал только __FILE__ и __LINE__, (гуглением __func__ вышел на __PRETTY_FUNCTION__ ).

Kroz ★★★★★ ()
Ответ на: комментарий от AndreyKl

код нечитаем.

Я так понял, что код не читаем по двум причинам:
1. Слишком большие отступы, нужно было убрать табы и заменить на двойные пробелы (у меня редактор это делает на автомате).
2. Нужно было убрать все макросы и дебагинг.
Я, конечно, догадываюсь, что мой код по оформлению, не дотягивает до (каких-то там) корпоративных стандартов, но нечитабельным его не назовешь (я видел намного хуже намного чаще).

чувак который предложил грепать рулит и педалит.

Я выше объяснил почему не рулит. Каждый привык к своему способу (хотя я упорно заставляю себя менять привычки, если есть на то веские аргументы).
Твой способ слишком громоздок и не позволяет одним махом включать/выключать логи для конкретной функции.

ну и тебе похоже уже разъяснили в чём была твоя проблема...

Нет, не разъяснили. Если ты о топике - есть только гипотеза, что на создание тредов уходило слишком много времени. Вторая гипотеза - игры с affinity. Для себя вынес, что многопоточность не так проста, как кажется на поверхности, и нужно сначала потренироваться на кошках. И что нужно освоить что-то типа профайлера (надеюсь, я правильно понял что это) и научиться замерять время для каждого потока.

Kroz ★★★★★ ()
Ответ на: комментарий от ziemin

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

Ида - код гавно.

Обоснуй с примерами как нужно с твоей точки зрения.

Kroz ★★★★★ ()
Последнее исправление: Kroz (всего исправлений: 1)
Ответ на: комментарий от Kroz

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

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

array.put("func1");
//array.put("func2");
//array.put("func3");
array.put("func4");
//array.put("func5");

и включай-выключай что хочешь комментом как у тебя. но только у тебя теперь управляется всё из одного места при этом!!!!!1111одынодынпыщьпыщь (и это место в данном случае, заметь пожалуйста, не жопа как в твоём коде).

и у меня вопрос по ходу пьессы так сказать. если у меня код «слишком громоздкий» то как назыается то что навоял ты? «копец-на-холодец с включалкой в жопе» что ли?

AndreyKl ★★★★★ ()
Последнее исправление: AndreyKl (всего исправлений: 2)
Ответ на: комментарий от Kroz

Для себя вынес, что многопоточность не так проста, как кажется на поверхности, и нужно сначала потренироваться на кошках.

да нет, ты просто где-то накосячил совершенно подетски.

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

ps. то что она не проста это факт и там довольно много мест где чёрт ногу сломит и поймать трудно бывает проблему. но именно в твоём случае ты просто делаешь что то не так очень банально, не более того. я уверен на 99,999%.

AndreyKl ★★★★★ ()
Последнее исправление: AndreyKl (всего исправлений: 1)
Ответ на: комментарий от Kroz

Пажалста:

  • Идиотские идентификаторы, не отражающие сути. Приходится лезть в код функций и т.д. И вводящие в заблуждение кстати.
  • Идиотские комментарии, которых уж лучше бы совсем не было.
  • Алгоритм размазан по нескольким функциям неестественно.
  • Какие-то левые функции на две трети кода.
  • Вычисления констант в условиях циклов.
  • Отладочные сообщения, которые поёмешь только ты. Посмотри dmesg.

и это всё в, считай 20 строках работающего кода!

ziemin ★★ ()

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

Дело в том, что /development/ ЛОРа не является сообществом профессиональных разработчиков. Профессионалы (то есть те, кто владеет технологиями на высоком уровне и зарабатывает на жизнь разработкой ПО) здесь в подавляющем меньшинстве и, я бы сказал, на птичьих правах. Абсолютное большинство — это тролли, диванные теоретики, доморощенные гуру, форумные трепачи, лисперы, хаскелисты и прочие ёбнутые на голову адепты маргинальщины, фрики, школьники, хипсторы, петросяны, IT-эзотерики, IT-шарлатаны, IT-небыдло и так далее. Здесь в воздухе густо пахнет мамкиным борщом и нонконформизмом. Здесь модно поливать говном все практические, промышленные технологии и подходы (к которым, несомненно, относится и С++). Поэтому вместо экспертного мнения ты получишь здесь 100500 тонн говна на multithreading и 9000 советов учить лисп, хаскель, Smalltalk, Brainfuck, Agda2, Coq и Epigram. Разве это то, чего ты хочешь?

Лично я бы советовал обратиться к англоязычным сайтам и литературе.

anonymous ()
Ответ на: комментарий от Kroz

если есть на то веские аргументы

Аргумент простой: сейчас у тебя 50 строк кода и компилируешь ты его по каждому чиху и только у себя. А когда у тебя будет уже несколько тысяч строк кода, при том, что хуже, у тебе придётся кому-то дать свою программу потестировать, и у тебя не будет возможности всячески включать-выключать логи перекомпилированием, да и само перекомпилирование будет занимать не пол секукнды, а пару минут... В общем, ты тогда поймёшь что проще сам :) Но, в любом случае, говорю сразу, перекомпилияция по каждому чиху - не метод.

пс решать естессно тебе, чё уж там, наше дело предложить :)

invy ★★★★★ ()
Ответ на: комментарий от anonymous

анонимус, кстати, пример грамотного профи. дал совет по теме. ни слова лишнего не сказал. молодец!

и да, вроде в треде никто не сказал что с++ говно. впроде как большинство очень вежливо намекнуло что код у топикстартера не являет собой пример не то что совершенства, но даже достаточной читаемости.

и кстати о борще. лично я его люблю.

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

AndreyKl ★★★★★ ()
Последнее исправление: AndreyKl (всего исправлений: 1)
Ответ на: комментарий от invy

не пол секукнды, а пару минут...

пока пару жить ещё можно и с такой «системой». а вот когда по пол часа компилируется, тут уже хоть вешайся..

AndreyKl ★★★★★ ()
Ответ на: комментарий от pulo

Забыли TDD, ЭТО тут многие любят.. кроме меня:)

Что не так с TDD? Зрелый, оправдавший себя подход, принятый индустрией. Разумеется, если без фанатизма.

anonymous ()
Ответ на: комментарий от AndreyKl

если у меня код «слишком громоздкий» то как назыается то что навоял ты?

Упрощенная версия:

#define DEBUG
void Function()
{
  ...
#ifdef DEBUG
  cout << "This is a log message" ;
#endif
  ...
}
Сложно?

Kroz ★★★★★ ()
Ответ на: комментарий от anonymous

Интересно какой именно индустрией? конторами клепающими сайты? кодерами на пехапе?

Представляю какая простыня кода тут была бы по TDD...

Топикстартеру: 2 тоже простое число;)

pulo ()
Ответ на: комментарий от AndreyKl

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

Убрал.
Укажешь на gap - буду признателен. Напомню, что проблема в том, что не грузит оба ядра. Еще к слову: по данным time многопоточный код (Initiate3) работает медленне двух предыдущих алгоритмов (Initiate1 и Initiate2).

Kroz ★★★★★ ()
Ответ на: комментарий от Kroz

так а у меня то получается лучше, погляди сам

void f() {
...
debug("This is a log message", __func__);
...
}

при этом у тебя сложно, хоть тебе и не кажется что сложно. потому что чтобы включить/выключить отладку надо посетить кучу мест. представь, например, что тебе нужно включить отладку у трёх методов и выключить у двух... поскакал казак по степи топикстартер по коду. я уж молчу про перекомпиляцию ради включения лога о чём говорил тут предлагавший греп. Говорю тебе ещё раз - греп рулит. Ну или моё маленькое прекрасненькое уютненькое решение для любящих поконпелять :)

AndreyKl ★★★★★ ()
Последнее исправление: AndreyKl (всего исправлений: 3)
Ответ на: комментарий от Kroz

Убрал.

чёрд, ты прям заставляешь меня читать код.. полез :)

AndreyKl ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.