Особенности языка mql5, тонкости и приёмы работы - страница 53

 
Как быстро сложить много строк (например, сгенерировать торговый отчет в string)
class SUM_STRING
{
protected:
  uchar Data[];
    
public:
  SUM_STRING( const int Reserve = 0 )
  {
    ::ArrayResize(this.Data, 1, Reserve);
  }

  void operator +=( const string Str )
  {
    ::StringToCharArray(Str, this.Data, ::ArraySize(this.Data) - 1);
  }
  
  const string Get( void ) const
  {
    return(::CharArrayToString(this.Data));
  }
};

// Классическое складывание
ulong SumString1( string TmpStr, const int Amount )
{
  const ulong StartTime = GetMicrosecondCount();

  string Str = "";

  for (int i = 0; i < Amount; i++)
    Str += TmpStr;

  return(GetMicrosecondCount() - StartTime);
}

// Быстрое складывание
ulong SumString2( string TmpStr, const int Amount )
{
  const ulong StartTime = GetMicrosecondCount();

  SUM_STRING SumStr(Amount * StringLen(TmpStr) + 1);

  for (int i = 0; i < Amount; i++)
    SumStr += TmpStr;

  const string Str = SumStr.Get();

  return(GetMicrosecondCount() - StartTime);
}

// #property script_show_inputs

input int inLen = 400;    // Длина строки, которую будем добавлять
input int inAmount = 1e4; // Сколько раз будем складывать

// Как быстро сложить много строк (например, сгенерировать торговый отчет в string)
void OnStart()
{  
  string Str;
  
  StringInit(Str, inLen, 1);
  
  Print(SumString1(Str, inAmount)); // Время классического решения
  Print(SumString2(Str, inAmount)); // Время альтернативного решения
  Print(SumString2(Str, inAmount)); // Почему эта строка всегда выполняется заметно быстрее, чем предыдущая?
}

Результат

2748404
12678
10388

В 250 раз быстрее и это не предел!


ЗЫ Красным отмечен факт, который никак не удается объяснить.

 
fxsaber:
Как быстро сложить много строк (например, сгенерировать торговый отчет в string)

Результат

В 250 раз быстрее и это не предел!


ЗЫ Красным отмечен факт, который никак не удается объяснить.

Особенности работы пула памяти, при первом вызове SumString2 в пул памяти "насыщается" памятью из системы, при повторном, память у системы больше не запрашивается.

Рекомендую поправить SumString1

ulong SumString1( string TmpStr, const int Amount )
{
  const ulong StartTime = GetMicrosecondCount();

  string Str;
  StringInit(Str,Amount * StringLen(TmpStr) + 1);            << обеспечим строке приёмный буфер

  for (int i = 0; i < Amount; i++)
    Str += TmpStr;

  return(GetMicrosecondCount() - StartTime);
}
 
Ilyas:

Особенности работы пула памяти, при первом вызове SumString2 в пул памяти "насыщается" памятью из системы, при повторном, память у системы больше не запрашивается.

Рекомендую поправить SumString1

Спасибо! Могли бы Вы отразить понятие приемного буфера хоть как-то в Справке. Сейчас есть только StringBufferLen, из описания которого ничего не ясно.

 
fxsaber:

Спасибо! Могли бы Вы отразить понятие приемного буфера хоть как-то в Справке. Сейчас есть только StringBufferLen, из описания которого ничего не ясно.

Дык вроде ж всё понятно, речь идёт о выделенной памяти под стринг.  Это просто Илья как-то запутанно изъясняется про "насыщение памятью из системы" )

Я кстати тоже не знал о такой особенности, что локальная переменная использует выделенную ранее память.  Так то получается, что нет особого смысла городить собственную оптимизацию, если только речь не идёт об однократном тяжёлом расчёте.  Ну и неясен вопрос с освобождением этой памяти. Освобождается ли она в процессе выполнения программы или только при деинициализации?

 
Alexey Navoykov:

Дык вроде ж всё понятно, речь идёт о выделенной памяти под стринг.  Это просто Илья как-то запутанно изъясняется про "насыщение памятью из системы" )

Конечно, понятно, когда Илья привел код. В Справке об этом, к сожалению, ни слова.

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

Как раз столкнулся с таким случаем, что секунды уходили на формирование строки. А после оптимизации - миллисекунды. Но вариант Ильи, конечно, самый быстрый. Если бы Справка была идеальной, не городил бы, конечно.

 
fxsaber:

Конечно, понятно, когда Илья привел код. В Справке об этом, к сожалению, ни слова.

Как раз столкнулся с таким случаем, что секунды уходили на формирование строки. А после оптимизации - миллисекунды. Но вариант Ильи, конечно, самый быстрый. Если бы Справка была идеальной, не городил бы, конечно.

Ну что касается StringInit, то о нём вроде давно известно.  Я тоже его всегда использую при больших объёмах.  Если не знаю точной длины складываемых строк, то беру приблизительную

 

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Библиотеки: TesterBenchmark

fxsaber, 2017.08.15 19:31

ЗЫ2 А что это за тормоза в 1648 на первом проходе каждой пачки? В 1643 было так

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Особенности языка mql5, тонкости и приёмы работы

fxsaber, 2017.08.15 17:16

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

Как будто в 1648 тестер тут же делает NewTick-событие. Что, конечно, неправильно.
 

В тестере IsStopped() всегда возращает ноль (не false). Поэтому рассчитывать на взаимодействие этого флага с ExpertRemove(), как на реале, ошибочно в тестере.

 
StringInit(Str);
Str = NULL;

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

 

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Библиотеки: TesterBenchmark

fxsaber, 2017.09.05 09:36

Тупая замена PositionSelect на PositionGetTicket поднимает скорость бэктеста на 7%!

И это на неттинг-счете!
Причина обращения: