事件流。 如何控制并使事件闲置?(+已解决)

 

有一个问题--我需要更新一些功能,但要比MQL的定时器快--少于1秒。
解决方案-- OnChartEvent 做了事件发送给自己--EventChartCustom

所有工作都非常快。但第二个问题是,消息队列没有时间被清理。

例如,当点击对象时,事件CHARTEVENT_OBJECT_CLICK 不会立即出现,而是在所有先前的事件从队列中删除后才出现。
正如你所理解的,事件队列被EventChartCustom 堵塞了

基本上,我们需要实现对一些函数的严格控制 的更新,但同时又要

- 没有像while (true)那样无休止的循环。
- 但是,OnChartEvent 也会在图表事件发生时立即响应。

在这种情况下,该怎么做?也许用EventChartCustom 发送控制还有其他选择

换句话说--如何使MQL调用一些函数超过1秒,但没有任何队列。

----------

最简单的解决方案(但需要开发人员参与)是允许从事件队列中接收下一个事件,但不退出OnChartEvent 函数。

也就是说,我希望我的EventChartCustom中的所有空事件都能被一次性清理掉。而且不允许用左边的事件加载队列。

 

如果你只在处理OnChartEvent 时发送一个事件,从逻辑上讲,队列应该不会溢出。你不会在任何地方举办这种活动,是吗?

你也可以通过事件路由来发送该事件。即有一个指标或其他专家顾问,它只需要向发送者发送对某些事件的响应事件。

 
TheXpert:

如果你只在处理OnChartEvent 时发送一个事件,从逻辑上讲,队列应该不会溢出。

不,它只是自己溢出来了。EventChartCustom OnChartEvent 被调用 并且有密集的事件流。一方面,这是你需要的,但另一方面,图表事件需要很长时间才能通过。

你也可以通过事件板发送事件。即,有一个诱导者,或其他顾问,只需要将某些事件的响应事件发送给发送者。

我曾这样想过,但没有想出什么办法。描述一下交换计划?
 
sergeev:
我想过这个问题,但没有想出办法。请描述交换计划。

我们有一个指标(不同的线程,它可能更好)。它抓住了事件1。在这种情况下,最好能将所有必要的信息传回。

土耳其向事件1发送者发送事件2。

EA捕捉到事件2并再次发送事件1,对于事件1,EA根本没有任何反应。

而如果我们使用一个假的专家顾问,我们将有一个好的睡眠时间。

 

这个想法很清楚。但它不会起作用。它将类似于错过一个事件。

但我刚刚测试了这样一个简单的算法。

int rest=0;
int all=0;
bool click=false;
//------------------------------------------------------------------    OnInit
int OnInit() { EventChartCustom(0, 0, 0, 0, ""); return(0); }
//------------------------------------------------------------------    OnChartEvent
void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam)
{
        if (id==CHARTEVENT_OBJECT_CLICK) click=!click;
        if (!click) { EventChartCustom(0, 0, 0, 0, ""); all++; }
        else rest++;
        
        string txt="all="+string(all)+"  rest="+string(rest);
        SetButton(0, "btn", 0, txt, clrWhite, clrDarkBlue, 150, 150, 200, 50, 0, 9, "Tahoma", click);
        ChartRedraw(0);
}
//------------------------------------------------------------------ SetButton
void SetButton(long achart, string name, int wnd, string text, color txtclr, color bgclr, int x, int y, int dx, int dy, int corn=0, int fontsize=8, string font="Tahoma", bool state=false)
{
        ObjectCreate(achart, name, OBJ_BUTTON, wnd, 0, 0); ObjectSetInteger(achart, name, OBJPROP_CORNER, corn); 
        ObjectSetString(achart, name, OBJPROP_TEXT, text); ObjectSetInteger(achart, name, OBJPROP_STATE, state);
        ObjectSetInteger(achart, name, OBJPROP_COLOR, txtclr); ObjectSetInteger(achart, name, OBJPROP_BGCOLOR, bgclr); ObjectSetInteger(achart, name, OBJPROP_BORDER_COLOR, clrNONE);
        ObjectSetInteger(achart, name, OBJPROP_FONTSIZE, fontsize); ObjectSetString(achart, name, OBJPROP_FONT, font);
        ObjectSetInteger(achart, name, OBJPROP_XDISTANCE, x); ObjectSetInteger(achart, name, OBJPROP_YDISTANCE, y);
        ObjectSetInteger(achart, name, OBJPROP_XSIZE, dx); ObjectSetInteger(achart, name, OBJPROP_YSIZE, dy);
        ObjectSetInteger(achart, name, OBJPROP_SELECTABLE, false);
        ObjectSetInteger(achart, name, OBJPROP_BORDER_TYPE, 0);
        ObjectSetString(achart, name, OBJPROP_TOOLTIP, text);
}

所有的事件都能正常工作。没有滞后性。

但如果你在一行中放入两次(或更多)EventChartCustom

if (!click) { EventChartCustom(0, 0, 0, 0, ""); EventChartCustom(0, 0, 0, 0, ""); all++; }

将会有两倍的滞后。

因此,我得出结论,一切工作都是正常的,是我的代码在某处有双EventChartCustom 调用 ,而这个事件是累积的。

我将在代码中寻找。现在,这个话题可以结束了。

 
sergeev:

这个想法很清楚。但这是行不通的。这就相当于错过了一次活动。

不,是的,我的意思是,事件1和2的图表是不同的。

(1) 我怀疑对于不同的线程,它的工作速度会慢很多。

(2) 你可以睡觉,如果顾问。

嗯,还有2倍(至少)的速度。

 
свой OnCustomTimer в миллисекундах


#define MSECTIMER 100
#define TIMEREVENT 111
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- create timer
   EventSetTimer(60);
   EventSetCustomTimer(MSECTIMER);
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- destroy timer
   EventKillTimer();

  }
//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
//---

  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void EventSetCustomTimer(int msec) 
  {
   EventChartCustom(0,TIMEREVENT,msec,NULL,NULL);
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
   static uint lasttick=0;
   if(id==CHARTEVENT_CLICK) 
     {
      Print("Click");
     }

   if(id==CHARTEVENT_CUSTOM+TIMEREVENT) 
     {
      uint current=GetTickCount();
      if(lasttick+lparam<=current) 
        {
         lasttick=current;
         OnCustomTimer();
        }
     }
   EventSetCustomTimer(MSECTIMER);
  }
//+------------------------------------------------------------------+


void OnCustomTimer() 
  {
//
  }
//+------------------------------------------------------------------+
看了之前的代码--是的,
OnChartEvent 可以使用一个捎带,它默认为
EventSetCustomTimer
 
TheXpert:

不,是的,我的意思是,事件1和2的图表是不同的。

(1) 有一种怀疑是,对于不同的线程,它的工作速度会慢很多。

(2)你可以睡觉,如果EA。

嗯,还有2倍(至少)的速度。


他们说的是真的--早上更聪明。:) 我已经解决了这个问题。这甚至是非常优雅的结果。

- 让我们来介绍一下已发信息的计数器 event_idle

- 发送事件时,将此计数器发送到LPARAMEventChartCustom(chart, VM_IDLE, event_idle, 0, "")。

- 然后在OnChartEvent处理程序中,耙出所有VM_IDLE消息,直到传入的LPARAM参数等于当前的event_idle。

像这样

ulong event_idle=0; bool bidle;
void OnChartEvent(int iview, int id, long lparam, double dparam, string sparam)
{
    if (id==CHARTEVENT_CUSTOM+VM_IDLE)
    {
        if (event_idle>(ulong)lparam || bidle) { bidle=event_idle>(ulong)lparam; if (bidle) return; event_idle=0; } // если последнее посланное больше чем пришедшее, то сразу выходим
        event_idle++;
        ChartRedraw(m_chart); // обновили чарт
        EventChartCustom(m_chart, VM_IDLE, (long)event_idle, 0, ""); // отправили событие с указанием последнего счетчика
        return; 
    }
    EventChartCustom(m_chart, VM_IDLE, (long)event_idle, 0, ""); // отправили событие  с указанием последнего счетчика

    /*
        обработка остальных событий
    */
}

这样一来,这个事件就永远不会出现超标,因为它们都会被刮掉。

现在,在没有事件队列枚举的情况下,速度也很好:)

 
sergeev:

...但第二个问题出现了,即消息队列未能清除。 溢出。

我找不到问题的答案:事件队列溢出如何影响RAM大小?如果事件队列原来是溢出的,那么溢出的事件会去哪里?保留给那些刚好 "离开历史 "的事件的部分记忆是否被释放出来?

也许我的问题在术语上并不正确,但(我希望)它们抓住了问题的本质。

 
Yedelkin:

我找不到问题的答案:事件队列溢出如何影响RAM大小?如果事件队列出现溢出,溢出队列的事件会去哪里?

这就是问题的关键:他们不这样做,他们积累起来。
 
sergeev:
这就是问题的关键:他们没有去任何地方。

也就是说,如果事件队列变满,那么溢出队列的事件就会 "吃掉 "RAM,逐渐增加消耗的RAM的大小?但这是错误的。看来,那些 "吹过队列 "的事件最终应该释放出为它们保留的内存。

......一年后,我仍然没有设法得到关于事件队列规模的连贯答案。因此,仍然不清楚应该以何种频率发送用户事件,以便它们不会溢出终端事件的队列......

Документация по MQL5: Стандартные константы, перечисления и структуры / Константы графиков / Типы событий графика
Документация по MQL5: Стандартные константы, перечисления и структуры / Константы графиков / Типы событий графика
  • www.mql5.com
Стандартные константы, перечисления и структуры / Константы графиков / Типы событий графика - Документация по MQL5