Características del lenguaje mql5, sutilezas y técnicas - página 53

 
Cómo sumar muchas cadenas rápidamente (por ejemplo, generar un informe comercial en cadena)
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 = 1 e4; // Сколько раз будем складывать

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

El resultado

2748404
12678
10388

250 veces más rápido, ¡y eso no es el límite!


HH El hecho marcado en rojo no se puede explicar de ninguna manera.

 
fxsaber:
Cómo sumar rápidamente muchas cadenas (por ejemplo, generar un informe comercial en cadena)

El resultado

250 veces más rápido, ¡y eso no es el límite!


ZS El rojo marca un hecho que no se puede explicar de ninguna manera.

La peculiaridad del pool de memoria, cuando se llama a SumString2 por primera vez, el pool de memoria está "saturado" de memoria del sistema, la segunda vez, la memoria ya no se solicita al sistema.

Recomiendo corregir 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:

El pool de memoria es especial, la primera vez que se llama a SumString2 al pool de memoria se "satura" con memoria del sistema, la segunda vez no se vuelve a pedir memoria al sistema.

Recomiendo corregir SumString1

Gracias. Podrían reflejar la noción de un buffer de recepción al menos de alguna manera en la Ayuda. Ahora mismo sólo hayStringBufferLen cuya descripción no dice nada.

 
fxsaber:

Gracias. Podrían explicar el concepto de buffer de recepción al menos de alguna manera en la Ayuda. Ahora mismo sólo existe StringBufferLen, cuya descripción no tiene ningún sentido.

Está bastante claro, estamos hablando de la memoria asignada para el encadenamiento. Es que la explicación de Elías sobre la "saturación de la memoria del sistema" es algo confusa )

Por cierto, tampoco sabía de esa característica, que una variable local utiliza la memoria previamente asignada. Así que resulta que no tiene mucho sentido hacer tu propia optimización, a menos que estemos hablando de un solo cálculo pesado. El tema de la liberación de esta memoria tampoco está claro. ¿Se libera durante el tiempo de ejecución o sólo durante la desinicialización?

 
Alexey Navoykov:

Está claro, estamos hablando de la memoria asignada para la cadena. Es que Ilya lo explica de forma muy complicada sobre la "saturación de la memoria del sistema". )

Por supuesto, es comprensible cuando Ilya citó el código. Por desgracia, la Ayuda no dice nada al respecto.

Por cierto, yo tampoco conocía esta característica específica: una variable local utiliza la memoria asignada anteriormente. Así que resulta que no tiene mucho sentido crear una optimización propia a menos que se trate de un solo cálculo pesado.

Acabo de enfrentarme a un caso de este tipo en el que he tardado segundos en formar una cadena. Pero después de la optimización me tomó milisegundos. Pero la variante de Ilya es, por supuesto, la más rápida. Si mi ayuda fuera perfecta, no lo habría hecho.

 
fxsaber:

Por supuesto, es comprensible cuando Ilya dio el código. Lamentablemente, no hay ninguna palabra al respecto en la Ayuda.

Acabo de encontrarme con un caso de este tipo en el que se tardó segundos en formar una cadena. Pero después de la optimización se hizo en milisegundos. Pero la variante de Ilya es, por supuesto, la más rápida. Si nuestra ayuda fuera ideal, no lo habría hecho.

Bueno, hablando de StringInit, se sabe desde hace mucho tiempo. Yo también lo uso siempre para grandes cantidades. Si no sé la longitud exacta de las líneas que hay que añadir, utilizo la longitud aproximada.

 

Foro sobre comercio, sistemas de comercio automatizados y pruebas de estrategias

Bibliotecas: TesterBenchmark

fxsaber, 2017.08.15 19:31

ZS2 ¿Qué pasa con los frenos en 1648 en la primera pasada de cada paquete? En 1643 era así.

Foro sobre trading, sistemas de trading automatizados y pruebas de estrategias de trading

Características del lenguaje mql5, sutilezas y trucos

fxsaber, 2017.08.15 17:16

En la primera pasada de un paquete de trabajo de Agente (por ejemplo, una sola ejecución de probador), el tiempo entre la ejecución del EA y el primer evento NewTick puede tardar unos segundos. En las siguientes pasadas del paquete, este tiempo es cero.

Como si en 1648 el probador hiciera inmediatamente un evento NewTick. Lo cual, por supuesto, es un error.
 

En el probador, IsStopped() siempre devuelve cero(no falso). Por lo tanto, es erróneo esperar que esta bandera interactúe con ExpertRemove() como en el mundo real en el probador.

 
StringInit(Str);
Str = NULL;

La primera línea se ejecuta más rápido que la segunda con idénticos resultados.

 

Foro sobre comercio, sistemas de comercio automatizados y pruebas de estrategias

Bibliotecas: TesterBenchmark

fxsaber, 2017.09.05 09:36

Sustituir estúpidamente PositionSelect por PositionGetTicket aumenta la velocidad de backtest en un 7%.

¡Y eso en una cuenta de red!