#include <fxsaber\Sequence.mqh> // https://www.mql5.com/ru/code/31446 #define PRINT(A) Print(#A + " = " + (string)(A)) input datetime inFrom = D'2020.09.01'; // С какой даты анализировать историю void OnInit() { SEQUENCE Sequence; // Последовательный запуск расчетов // if (Sequence.Init()) // Раскомментируйте для последовательного выполнения. { MqlTick Ticks[]; PRINT(CopyTicksRange(_Symbol, Ticks, COPY_TICKS_ALL, (long)inFrom * 1000)); PRINT(TerminalInfoInteger(TERMINAL_MEMORY_USED)); Sleep(10000); // Ждем освобождения CopyTicks-данных. } }
Запускаем его на нескольких чартах разных символов. Для автоматизации сего действия использовал этот скрипт с inAmount = 5.
Результат.
2020.10.13 13:26:53.199 Test9 (AUDCAD,H1) CopyTicksRange(_Symbol,Ticks,COPY_TICKS_ALL,(long)inFrom*1000) = 5406953 2020.10.13 13:26:53.326 Test9 (AUDCAD,H1) TerminalInfoInteger(TERMINAL_MEMORY_USED) = 2838 2020.10.13 13:26:53.528 Test9 (EURCHF,H1) CopyTicksRange(_Symbol,Ticks,COPY_TICKS_ALL,(long)inFrom*1000) = 3430958 2020.10.13 13:26:53.807 Test9 (EURCHF,H1) TerminalInfoInteger(TERMINAL_MEMORY_USED) = 3144 2020.10.13 13:26:53.924 Test9 (EURUSD,H1) CopyTicksRange(_Symbol,Ticks,COPY_TICKS_ALL,(long)inFrom*1000) = 4244747 2020.10.13 13:26:54.214 Test9 (EURUSD,H1) TerminalInfoInteger(TERMINAL_MEMORY_USED) = 3464 2020.10.13 13:26:54.344 Test9 (AUDCHF,H1) CopyTicksRange(_Symbol,Ticks,COPY_TICKS_ALL,(long)inFrom*1000) = 4327679 2020.10.13 13:26:54.702 Test9 (AUDCHF,H1) TerminalInfoInteger(TERMINAL_MEMORY_USED) = 3797 2020.10.13 13:26:54.864 Test9 (GBPCHF,H1) CopyTicksRange(_Symbol,Ticks,COPY_TICKS_ALL,(long)inFrom*1000) = 5340006 2020.10.13 13:26:55.457 Test9 (GBPCHF,H1) TerminalInfoInteger(TERMINAL_MEMORY_USED) = 4308 2020.10.13 13:26:55.666 Test9 (EURAUD,H1) CopyTicksRange(_Symbol,Ticks,COPY_TICKS_ALL,(long)inFrom*1000) = 7730155 2020.10.13 13:26:55.756 Test9 (EURAUD,H1) TerminalInfoInteger(TERMINAL_MEMORY_USED) = 4316
Больше 4 Gb памяти потребовал Терминал для запуска этих шести советников. Заметьте, это нужно только для инициализации, но не для работы этих советников. Представьте, что запускаете Терминал с висящими советниками в нем. Если нет честных свободных 4 Gb RAM - почти катастрофа.
Теперь уберем комментарий этой строки в исходнике.
if (Sequence.Init()) // Раскомментируйте для последовательного выполнения.
Тем самым включив последовательную инициализацию советников.
Смотрим на результат (после перекомпиляции).
2020.10.13 13:27:24.002 Test9 (AUDCAD,H1) CopyTicksRange(_Symbol,Ticks,COPY_TICKS_ALL,(long)inFrom*1000) = 5406980 2020.10.13 13:27:24.021 Test9 (AUDCAD,H1) TerminalInfoInteger(TERMINAL_MEMORY_USED) = 1234 2020.10.13 13:27:35.407 Test9 (EURUSD,H1) CopyTicksRange(_Symbol,Ticks,COPY_TICKS_ALL,(long)inFrom*1000) = 4244772 2020.10.13 13:27:35.422 Test9 (EURUSD,H1) TerminalInfoInteger(TERMINAL_MEMORY_USED) = 1095 2020.10.13 13:27:46.886 Test9 (GBPCHF,H1) CopyTicksRange(_Symbol,Ticks,COPY_TICKS_ALL,(long)inFrom*1000) = 5340072 2020.10.13 13:27:46.905 Test9 (GBPCHF,H1) TerminalInfoInteger(TERMINAL_MEMORY_USED) = 1224 2020.10.13 13:27:58.293 Test9 (AUDCHF,H1) CopyTicksRange(_Symbol,Ticks,COPY_TICKS_ALL,(long)inFrom*1000) = 4327724 2020.10.13 13:27:58.310 Test9 (AUDCHF,H1) TerminalInfoInteger(TERMINAL_MEMORY_USED) = 1114 2020.10.13 13:28:09.683 Test9 (EURCHF,H1) CopyTicksRange(_Symbol,Ticks,COPY_TICKS_ALL,(long)inFrom*1000) = 3430999 2020.10.13 13:28:09.696 Test9 (EURCHF,H1) TerminalInfoInteger(TERMINAL_MEMORY_USED) = 1015 2020.10.13 13:28:21.339 Test9 (EURAUD,H1) CopyTicksRange(_Symbol,Ticks,COPY_TICKS_ALL,(long)inFrom*1000) = 7730313 2020.10.13 13:28:21.363 Test9 (EURAUD,H1) TerminalInfoInteger(TERMINAL_MEMORY_USED) = 1519
На запуске советников удалось уменьшить потребление памяти Терминалом более, чем на 2.5 Gb. Вероятность VPS-катастрофы (и слабых домашних машин) значительно уменьшилась.
Вот так оба запуска выглядят в динамике.
Последовательный запуск растянул общую инициализации по времени, но сумел удержать Терминал от огромного потребления ОЗУ.
На верхнем и нижнем графиках хорошо виден процесс параллельной инициализации(левый высокий пик) и шести последовательных инициализаций (шесть средних пиков).
ЗЫ Во время экспериментов выявился неприятный нюанс со Sleep - см. исходник.
То, как сейчас написано, подойдет только для однократной сериализации (каждый "желающий" после однократной обработки "отваливается"). Если нужно её делать многократно, то могут возникнуть проблемы из-за очередности вызовов таймеров (один "желающий" может занять ресурс последовательно несколько раз, а другой - ни раза). ИМХО, не хватает какой-либо реализации "очереди" и/или "приоритетов" на основе срока давности.
Да, очереди нет. Кто успел - того и тапки. Не заморачивался, т.к. самому нужна только инициализация. А если речь идет о какой-нибудь автооптимизации, то все же логично, что автор сделает механизм, как в примере из описания - PrevCalcTime.
Похоже, идея очереди - зло. Т.к. можно уйти в бесконечное ожидание.
Похоже, идея очереди - зло. Т.к. можно уйти в бесконечное ожидание.
Как и в любом случае - зависит от реализации. При правильной не должно быть такого.
Более критично то, что при текущей реализации и общем названии (без специализации, что это только для однократного инита) - проблемы обеспечены.
Как и в любом случае - зависит от реализации. При правильной не должно быть такого.
Один советник с таймером сутки, другой - секунда. Разве возможна в такой ситуация очередь?
Более критично то, что при текущей реализации и общем названии (без специализации, что это только для однократного инита) - проблемы обеспечены.
Один советник с таймером сутки, другой - секунда. Разве возможна в такой ситуация очередь?
Для конструктивной критики лучше какой-нибудь исходник привести. Например, пример из описания.Когда необходимости в очереди нет, она прозрачно переваривает запросы, как будто её нет.
Чтобы исходник привести, его надо сперва написать, даже если на основе описания ;-). Прямо сейчас примера пока нет.
Самый простой - вырожденный случай: достаточно в примере уменьшить период активации до 1с и будет происходить вызов только этого одного экземпляра (второй бесконечно ждет ресурса).
if ((TimeLocal() - PrevCalcTime >= 1 ) && // Если пришло время делать расчеты Sequence.IsFree()) // и вычислительные ресурсы свободны
Мы же не может гарантировать, что в каком-то клиенте не случится расчет длиннее периода запроса ресурса.
Более наглядный способ - добавить параметры:
input int timerMs = 100; input int periodSec = 10; input int calcMs = 1000;
Заменить на них константы в коде а-ля:
void OnTimer() { static datetime PrevCalcTime = 0; static int Amount = 0; // Количество расчетов SEQUENCE Sequence; // Последовательный запуск расчетов if ((TimeLocal() - PrevCalcTime >= periodSec) && // Если пришло время делать расчеты Sequence.IsFree()) // и вычислительные ресурсы свободны { PrevCalcTime = TimeLocal(); Sleep(calcMs); // Тяжелые расчеты. Print((string)ChartID() + " - " + __FUNCTION__ + ": " + (string)Amount++); } }
Потом нужно запустить 3 экземпляра с periodSec=2.
В результате получим, что два экземпляра отрабатывают как задумано, а один сильно от них отстает. Когда экспертов будет много и все эти временные задержки сложатся непредсказуемым образом, гарантировать захват ресурса в конкретном экземпляре будет невозможно.
Когда экспертов будет много и все эти временные задержки сложатся непредсказуемым образом, гарантировать захват ресурса в конкретном экземпляре будет невозможно.
Понимаю, о чем речь. Похоже, описание неоднозначное. Нужен был механизм определения наличия свободного ресурса с запретом использования его другим. С этим библа справляется на ура. А вот последовательность все же ложится на плечи автора советника. Универсального решения либо нет, либо оно очень громоздкое: когда на решение уходит больше времени, чем требуется всем частным применениям.
Совмещение с FileSelectDialog, чтобы при запуске Терминала не возникала каша из диалоговых окон.
#include <fxsaber\Sequence.mqh> // https://www.mql5.com/ru/code/31446 void OnInit() { SEQUENCE Sequence; // Последовательный запуск расчетов if (Sequence.Init()) // Дожидаемся освобождения вычислительных ресурсов. { string FileNames[]; ChartSetInteger(0, CHART_BRING_TO_TOP, 0, true); ChartGetInteger(0, CHART_WINDOW_HANDLE); // Сдвинули очередь. FileSelectDialog(MQLInfoString(MQL_PROGRAM_NAME) + " " + _Symbol + " " + EnumToString(_Period), NULL, NULL, FSD_ALLOW_MULTISELECT | FSD_FILE_MUST_EXIST, FileNames, NULL); ArrayPrint(FileNames); } }
Иногда требуется провести тяжелый расчеты сразу на нескольких запущенных советниках. Такой параллельный расчет способен убить торговлю не только на своем терминале, но и на параллельно работающих. Причина - критическая нагрузка CPU.
Чтобы этого не происходило, желательно делать подобные расчеты последовательно. Ниже схема, как это можно сделать.
// Пример последовательных тяжелых расчетов без прерывания остальных действий советника. #include <fxsaber\Sequence.mqh> // https://www.mql5.com/ru/code/31446 // Тяжелый расчет. void Calculate() { Print((string)ChartID() + " - Run."); Sleep(1000); Print((string)ChartID() + " - Done."); } void OnChartEvent( const int id, const long& lparam, const double& dparam, const string& sparam ) { switch (id) { case CHARTEVENT_KEYDOWN: // Если нажали на клавишу - отдаем приказы на расчет. Print(lparam); Print("Calculate All!"); for (long Chart = ::ChartFirst(); Chart != -1; Chart = ::ChartNext(Chart)) EventChartCustom(Chart, 0, 0, 0, NULL); break; case CHARTEVENT_CUSTOM: // Если пришел приказ на расчет. { SEQUENCE Sequence; // Последовательный запуск расчетов if (Sequence.IsFree()) // Вычислительные ресурсы свободны Calculate(); // Считаем else { Sleep(0); // https://www.mql5.com/ru/forum/170952/page207#comment_23627280 EventChartCustom(0, (ushort)(id - CHARTEVENT_CUSTOM), lparam, dparam, sparam); // Повторяем приказ себе же на расчет. } } } }
Результат параллельного запуска пяти таких советников.
2021.07.25 12:34:48.823 Calculate All! 2021.07.25 12:34:48.825 132503570123939383 - Run. 2021.07.25 12:34:49.844 132503570123939383 - Done. 2021.07.25 12:34:49.844 132503570123939385 - Run. 2021.07.25 12:34:50.857 132503570123939385 - Done. 2021.07.25 12:34:50.858 132503570123939382 - Run. 2021.07.25 12:34:51.872 132503570123939382 - Done. 2021.07.25 12:34:51.872 132503570123939384 - Run. 2021.07.25 12:34:52.891 132503570123939384 - Done. 2021.07.25 12:34:52.892 132503570123939381 - Run. 2021.07.25 12:34:53.907 132503570123939381 - Done.
Такое решение хорошо тем, что не прерывается выполнение других функций советника.
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Sequence:
Последовательный запуск расчетов в параллельно-выполняющихся программах
Автор: fxsaber