Merkmale der Sprache mql5, Feinheiten und Techniken - Seite 53

 
Wie man viele Strings schnell zusammenzählt (z.B. einen Handelsbericht in einem String erstellen)
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)); // Почему эта строка всегда выполняется заметно быстрее, чем предыдущая?
}

Das Ergebnis

2748404
12678
10388

250 Mal schneller, und das ist noch nicht alles!


HH Die rot markierte Tatsache kann in keiner Weise erklärt werden.

 
fxsaber:
Wie man schnell viele Strings zusammenzählt (z.B. einen Handelsbericht in einem String erstellen)

Das Ergebnis

250 Mal schneller, und das ist noch nicht alles!


ZS Rot markiert eine Tatsache, die sich nicht erklären lässt.

Die Besonderheit des Speicherpools ist, dass beim ersten Aufruf von SumString2 der Speicherpool mit Speicher aus dem System "gesättigt" ist, beim zweiten Aufruf wird der Speicher nicht mehr aus dem System angefordert.

Ich empfehle die Korrektur von 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:

Beim ersten Aufruf von SumString2 in den Speicherpool wird dieser mit Speicher aus dem System "gesättigt", beim zweiten Aufruf wird der Speicher nicht mehr vom System angefordert.

Ich empfehle die Korrektur von SumString1

Ich danke Ihnen! Könnten Sie bitte den Begriff des Empfangspuffers wenigstens irgendwie in der Hilfe wiedergeben. Im Moment gibt es nurStringBufferLen, dessen Beschreibung nichts aussagt.

 
fxsaber:

Ich danke Ihnen! Könnten Sie bitte das Konzept des Empfangspuffers zumindest in der Hilfe erklären. Momentan gibt es nur StringBufferLen, dessen Beschreibung keinen Sinn ergibt.

Es ist ganz klar, dass es sich um Speicher handelt, der für die Zeichenketten zugewiesen wird. Es ist nur so, dass Elijahs Erklärung der "Speichersättigung des Systems" irgendwie verwirrend ist. )

Übrigens wusste ich auch nicht, dass eine lokale Variable zuvor zugewiesenen Speicher verwendet. Es macht also wenig Sinn, eine eigene Optimierung vorzunehmen, es sei denn, es handelt sich um eine einzelne schwere Berechnung. Auch die Frage der Freigabe dieses Speichers ist nicht klar. Wird sie während der Laufzeit oder nur bei der Deinitialisierung freigegeben?

 
Alexey Navoykov:

Es ist klar, dass wir über den zugewiesenen Speicher für String sprechen. Es ist nur so, dass Ilya es auf eine sehr komplizierte Art und Weise über "Speichersättigung des Systems" erklärt. )

Natürlich ist es verständlich, wenn Ilja den Kodex zitiert. Leider verliert er in der Hilfe kein einziges Wort darüber.

Übrigens war mir auch diese Besonderheit nicht bekannt: eine lokale Variable verwendet früher zugewiesenen Speicher. Es macht also wenig Sinn, eine eigene Optimierung zu erstellen, es sei denn, es handelt sich um eine einzelne schwere Berechnung.

Ich hatte gerade einen solchen Fall, als ich Sekunden brauchte, um eine Zeichenkette zu bilden. Aber nach der Optimierung brauchte ich nur noch Millisekunden. Aber die Variante von Ilya ist natürlich die schnellste. Wenn meine Hilfe perfekt wäre, hätte ich sie nicht so gemacht.

 
fxsaber:

Natürlich ist es verständlich, wenn Ilja den Code gegeben hat. Leider findet sich in der Hilfe kein Hinweis darauf.

Ich bin gerade auf einen solchen Fall gestoßen, bei dem es Sekunden dauerte, eine Zeichenkette zu bilden. Aber nach der Optimierung war es in Millisekunden erledigt. Aber die Variante von Ilya ist natürlich die schnellste. Wenn unsere Hilfe ideal wäre, hätte ich sie nicht so gemacht.

Nun, was StringInit betrifft, so ist es schon lange bekannt. Ich verwende es auch immer für große Mengen. Wenn ich die genaue Länge der hinzuzufügenden Zeilen nicht kenne, verwende ich die ungefähre Länge.

 

Forum zum Thema Handel, automatisierte Handelssysteme und Strategietests

Bibliotheken: TesterBenchmark

fxsaber, 2017.08.15 19:31

ZS2 Was hat es mit den Bremsen im Jahr 1648 beim ersten Durchgang jeder Partie auf sich? Im Jahr 1643 war es so.

Forum zum Thema Handel, automatisierte Handelssysteme und Testen von Handelsstrategien

Merkmale der Sprache mql5, Feinheiten und Tricks

fxsaber, 2017.08.15 17:16

Beim ersten Durchlauf eines Agentenauftragsbündels (z. B. einem einzelnen Testerlauf) kann die Zeit zwischen der Ausführung des EA und dem ersten NewTick-Ereignis einige Sekunden betragen. Bei den folgenden Durchläufen der Charge ist diese Zeit gleich Null.

Als ob der Prüfer im Jahr 1648 sofort ein NewTick-Ereignis erzeugt. Das ist natürlich falsch.
 

Im Testgerät gibt IsStopped() immer Null(nicht false) zurück. Daher ist es falsch zu erwarten, dass dieses Flag mit ExpertRemove() wie in der realen Welt des Testers interagiert.

 
StringInit(Str);
Str = NULL;

Die erste Zeile läuft schneller als die zweite mit identischen Ergebnissen.

 

Forum zum Thema Handel, automatisierte Handelssysteme und Strategietests

Bibliotheken: TesterBenchmark

fxsaber, 2017.09.05 09:36

Dummerweise erhöht das Ersetzen von PositionSelect durch PositionGetTicket die Backtest-Geschwindigkeit um 7%!

Und das auf einem Netting-Konto!