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

 
Nikolai Semko:

  1. ver mi post anterior
  2. Tengo muchos ejemplos con beneficios prácticos de microsegundos.

Hasta ahora sólo veo una desventaja mencionada de GetTickCount - el hecho de que está limitado por la resolución del temporizador del sistema, eso es un problema serio. Y el resto no tiene ninguna utilidad práctica en particular.Lo que estás haciendo son pruebas ultracortas de 15 milisegundos, nadie hace eso. Esos resultados son inestables. Tienes que hacer que la prueba dure al menos medio segundo y entonces estarás listo para hablar de algo.

 
Alexey Navoykov:

Nadie hace pruebas ultracortas de 15 milisegundos. Esos resultados son inestables. Se necesita al menos medio segundo para que la prueba dure, y luego se puede hablar de algo.

Te equivocas. Durante estos 15 milisegundos, la función GetTickCount( ) es llamada más de 6 000 000 veces.

Mi cálculo es correcto. El valor de GetTickCount() cambia cada 1/(2^6)=1/64 segundos (15625 microsegundos).
Desarrolladores, por favor confirmen.

 
ikolai Semko:

No es así.La función GetTickCount() es llamada más de 6 000 000 vecesen esos 15 milisegundos.

Cuando medimos el rendimiento de un código en funcionamiento (no un caballo esférico en el vacío), se ejecuta durante un intervalo de tiempo suficiente (cientos de milisegundos y más). La razón es que el rendimiento del sistema y la carga de trabajo cambian constantemente. Un momento es uno, mientras que el siguiente es diferente. Así que los resultados variarán mucho de una prueba a otra en intervalos cortos. Por eso necesitamos un intervalo más largo, pero los microsegundos ya no importan.

Además, tenemos comillas en milisegundos y los pings también están en milisegundos, así que no veo dónde hay que poner microsegundos. De todas formas, no es la cuestión.

Ahora tengo que inventar una solución, cómo salir de esta situación para evitar los inconvenientes de ambas funciones. No hay mucha esperanza para los desarrolladores.

 
Alexey Navoykov:

Ahora tenemos que averiguar cómo sortear las deficiencias de ambas funciones. No hay muchas esperanzas para los desarrolladores.

Creo que es posible con una fórmula como esta en primera aproximación:

ulong RealGetMicrosecondCount=(GetTickCount()-StartGetTickCount)*1000+x+GetMicrosecondCount()%15625;

Hasta ahora es sólo una idea en voz alta.

 

Algunos lugares donde utilizo microsegundos

  • TiempoCorriente personalizado, con una precisión aproximada de mseg.
  • Cálculo del tiempo de ejecución de la orden comercial.
  • Cálculo del tiempo de sincronización del historial de operaciones en la Terminal.
  • Retraso del terminal (~ 5 ms) - por cuánto está desfasado el tick en el momento de su OnTick/OnCalculate.
  • Corrección de OnTimer para que la distancia entre cualquier evento de tiempo (no sólo los vecinos) sea un múltiplo del tiempo especificado.
 
fxsaber:

Algunos lugares donde utilizo microsegundos

  • Ajustar OnTimer para que la distancia entre cualquier evento de tiempo (no sólo los adyacentes) sea un múltiplo del tiempo dado.

En segundo lugar, su error es el mismo que el de GetTickCount(), es decir, 15 milisegundos. Por eso el significado de los microsegundos no está muy claro. Supongamos que ha calculado un intervalo exacto al micro, pero en realidad llegará varios MILLONES de segundos después o antes.

 
Alexey Navoykov:

En segundo lugar, su error es el mismo que el de GetTickCount(), es decir, 15 milisegundos, por lo que no está muy claro cuál es el sentido de los microsegundos aquí. Supongamos que se calcula el intervalo con microprecisión, pero en realidad llegará varios MILLONES de segundos después o antes.


También los comandos se ponen en cola y la ejecución puede ser en 5 segundos...

 
Alexey Navoykov:

Ahora tenemos que averiguar cómo sortear las deficiencias de ambas funciones. No hay mucha esperanza para los desarrolladores.


Por desgracia.
sólo puedo ofrecerle esta variante de la función:

ulong RealMicrosecondCount()
  {
   static bool first=true;
   static ulong sum=0;
   static long delta;
   static long shift=0;
   static ulong  lasttickcount;
   ulong i=GetTickCount()+sum;
   ulong t=GetMicrosecondCount();
   if(first) // если первый вход, то вычисляем разницу GetMicrosecondCount и GetTickCount
     {
      lasttickcount=i;
      delta=((long)i*1000-long(t));
      first=false;
     }
   long curdelta=((long)i*1000-long(t));
   long d=curdelta-delta;
   if(fabs(d-shift)>20000) shift=d;
   if(i<lasttickcount) sum+=0x100000000;
   lasttickcount=i;
   return (t+shift);
  }

¿Por qué Alas?
Porque si se cambia la hora local o simplemente se cuelga el programa, se puede añadir un error de hasta 16 milisegundos a la funciónRealMicrosecondCount. No hay manera de evitarlo.
Pero no habrá consecuencias fatales cuando se cambie al horario de verano, al cambio de huso horario o a la actualización de la hora por Internet.

Archivos adjuntos:
 
Nikolai Semko:


Por desgracia,
sólo puede ofrecer esta versión de la función:

¿Por qué Alas?
Porque en caso de cambio de hora local o simplemente de cuelgue del software, se puede añadir un error de hasta 16 milisegundos a la funciónRealMicrosecondCount. No hay manera de evitarlo.
Pero no habrá consecuencias fatales cuando se cambie al horario de verano, al cambio de huso horario o a la actualización de la hora por Internet.

No lo he comprobado todavía, pero no estoy tan seguro de lo de los 16 ms. Cuando busqué en Google el tema, normalmente el error del temporizador del sistema se da como 10 ms, o 10-16 ms.

 

Aquí hay una variante que utiliza un temporizador winapi de alta resolución, dando una precisión de3,8e-07 segundos.

#import "Kernel32.dll"
  int QueryPerformanceCounter(ulong &lpPerformanceCount);
  int QueryPerformanceFrequency(ulong &lpFrequency);
#import


ulong QueryPerfomanceCounter() { ulong value;  if (QueryPerformanceCounter(value)) return value;  return 0; } 

ulong QueryPerformanceFrequency() { ulong freq;  if (QueryPerformanceFrequency(freq)) return freq;  return 0; }  


long GetPerfomanceCount_mcs()
{ 
  static long freq= QueryPerformanceFrequency();
  return freq ? QueryPerfomanceCounter()*1000000/freq : 0;
}


void OnStart()
{
  Print("Resolution of perfomance counter:  ",1.0/QueryPerformanceFrequency()," s");
  ulong  perfcount= GetPerfomanceCount_mcs(); 
  
  while(!IsStopped())
  {
    Comment((GetPerfomanceCount_mcs()-perfcount)/1000000.0);
    Sleep(10);
  }
}