неожиданное ускорение

4 января 2024, 16:27
Maxim Kuznetsov
0
48

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

В список вошли :

* StringSplit() что в общем-то неудивительно. Она и со строками возится и массивы аллоцирует. Функция удобная, но тормоз и из всех сил её надо избегать. 

* и внезапно двух-аргументный ArrayResize(); Для растущих динамических массивов, всегда надо рассчитывать третий параметр (сколько класть резерва). 


собственно произошло следующее: советник при работе постоянно пишет статистику в CSV файлы. А при старте или раз в день, её перечитывает и анализирует. Всё было неплохо, покуда файлы были небольшими.
А вот выросли до 20-30М и начались ТОРМОЗА. Увидел рекорд в 35 минут и пришлось патчить..

Во первых в цикле чтения был убран StringSplit

      while(!FileIsEnding(f)) {
         string s = FileReadString(f);
         if ( s == "" ) continue;
         /** don`t use slow StringSplit
         string spl[];
         if (StringSplit(s,';',spl)<6) continue;
         StringCharReplace(spl[5],',','.');
         StringCharReplace(spl[4],',','.');
         double spBuy=StringToDouble(spl[4]);
         double spSell=StringToDouble(spl[5]);
         */
         double spBuy=EMPTY_VALUE;
         double spSell=EMPTY_VALUE;
         int len=StringLen(s);
         int recnum=0;
         int recpos=0;
         for(int pos=0;pos<len;pos++) {
            if (s[pos]==';') {
               recnum++;
               recpos=pos+1;
            }
            if (recnum>3 && s[pos]==',') {
               StringSetCharacter(s,pos,'.');
               if (recnum==4) spBuy=StringToDouble(StringSubstr(s,recpos));
               else if (recnum==5) {
                  spSell=StringToDouble(StringSubstr(s,recpos));
                  break;
               }
            }
         }
   /// skipped
	ArrayPush(SellCollect,spSell); 
        ArrayPush(BuyCollect,spBuy);
  }

далее пропатчен основной виновник - ArrayPush , который добавлял элемент к массиву double. С целью указать резервирование в ArrayResize.
Странно, но "стандартная" функция ничего не резервирует вообще или какой-то мизер, поэтому инкремент размера (добавление 1-го элемента)  всегда вызывало переаллокацию и копирование всего массива.
bool ArrayPush(double &arr[],double value)

{
   int pos=ArraySize(arr);
   int reserved=4096 * (1+(pos+1)/4096);
   if (ArrayResize(arr,pos+1,reserved)!=pos+1) return false;
   arr[pos]=value;
   return true;
}

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

то после него вот, читается "пулей" и замедления от роста данных незаметны

ускорение в сотни раз. 

Поделитесь с друзьями: