Принципы написания скриптов

Страницы: 1
RSS
Принципы написания скриптов, Разделять или объединять?
 
Интересно мнение форумчан - как предпочитаете писать скрипты - все в одном файле или в виде конструктора - с подгрузкой отдельных файлов:
1. Отдельных функций/процедур (выставление заявки, считывание определенных данных и т.п.)
2. Отдельных классов (стратегия, позиция и т.п.)
 
Когда у Вас скрипт на тысячи, десятки тысяч строк, то писать в одном файле это смело.
А когда у Вас уже написано много скриптов, то придешь к модулям, т.к. каждый раз писать одно и тоже - это тоже смело.
При этом модуль - это не команда dofile в глобальном окружении, а нормальный модуль, подключаемый через require.
 
Цитата
Nikolay написал:
Когда у Вас скрипт на тысячи, десятки тысяч строк, то писать в одном файле это смело.
А когда у Вас уже написано много скриптов, то придешь к модулям, т.к. каждый раз писать одно и тоже - это тоже смело.
При этом модуль - это не команда dofile в глобальном окружении, а нормальный модуль, подключаемый через require.
Я тоже думаю об этом, но вижу определенные минусы - если блок кода выносишь в отдельную функцию / подключаемый модуль, мы теряем в загрузке памяти и скорости.
Вызов отдельной функции требует больше времени, чем исполнения кода в основном потоке. Универсальный функционал модуля требует бОльшего числа полей, которые должны удовлетворять самые широкие потребности.
Вот и интересно, кто как пишет, в каких ситуациях какие варианты предпочитают. Используют ли подгружаемые классы-таблицы... и т.п.
 
Медленней чем, что? У меня код с использованием десятка библиотек выполняется с одной итерация цикла где-то за 150-250 мс. При этом 60 мс - это установленная задержка.
Вариантов то нет, если надо писать сложный код. Это будут классы, модули, функциоанальный подход и т.д. Иначе будет совсем не разобраться через некоторое время, открыв свой же код.

Это относится не только к скриптам для Квика. Это общая практика программирования.
Цитата
Вызов отдельной функции требует больше времени, чем исполнения кода в основном потоке
А где, собственно, это функция вызывается... Все выполняется в дополнительном потоке Квика - функции main. Функцию можно только упрекать в расходовании памяти на дополнительные локальные переменные, но скорость то тут причем.

А универсальное пишем как раз для того, чтобы писать скрипты быстро и удобно. Иначе код придется писать с нуля каждый раз. А если ошибка, то что, исправлять в каждом файле.
 
Цитата
Иван Ру написал:
Интересно мнение форумчан - как предпочитаете писать скрипты - все в одном файле или в виде конструктора - с подгрузкой отдельных файлов:
1. Отдельных функций/процедур (выставление заявки, считывание определенных данных и т.п.)
2. Отдельных классов (стратегия, позиция и т.п.)
Существующая структура QLUA имеет существенный недостаток.
Все колбеки вызываются из одного потока и каждый из них повторяется в различных скриптах.
В итоге получается дублирование одних и тех же действий многократно.
Я устранил эту проблему и сделал механизм при котором колбеки в скриптах не повторяются,
а скрипты могут запускать функции друг у друга и получать данные из других скриптов..
-------------------------
В итоге не только повышается скорость, но и размер кода сокращается в десятки раз.
 
Цитата
Все колбеки вызываются из одного потока и каждый из них повторяется в различных скриптах.
В итоге получается дублирование одних и тех же действий многократно.

Согласен с предыдущим оратором.
 
Цитата
nikolz написал:
Цитата
Иван Ру написал:
Интересно мнение форумчан - как предпочитаете писать скрипты - все в одном файле или в виде конструктора - с подгрузкой отдельных файлов:
1. Отдельных функций/процедур (выставление заявки, считывание определенных данных и т.п.)
2. Отдельных классов (стратегия, позиция и т.п.)
Существующая структура QLUA имеет существенный недостаток.
Все колбеки вызываются из одного потока и каждый из них повторяется в различных скриптах.
В итоге получается дублирование одних и тех же действий многократно.
Я устранил эту проблему и сделал механизм при котором колбеки в скриптах не повторяются,
а скрипты могут запускать функции друг у друга и получать данные из других скриптов..
-------------------------
В итоге не только повышается скорость, но и размер кода сокращается в десятки раз.
Признаться, все более склоняюсь в сторону такой модели, в первую очередь из-за разрастания скрипта и усложнения его логики из-за чего работа и модификация скрипта становится все более затруднительной...
Полагаю можно использовать такую структуру:
- базовый скрипт, который определяет статус сессии и агрегирует информацию из коллбэков
- описание классов (стратегия, позиция и т.п.)
- типовые универсальные модули, например, удаление устаревшей части данных таблиц (цены, бид аск и т.п.), ежедневное определение ключевых временных точек сессии в формате posix, визуализация и логгирование информации и т.п.
- собственно скрипты с описанием стратегий, логики определение сигналов на вход и выход и сопутствующих действий...

Если кто-то поделится своим видением организационной структуры - буду признателен

Поясню свое прежнее беспокойство - у меня большинство скриптов работает одновременно с большим числом инструментов, предполагается большой объем расчетов, опасаюсь, что в тех случаях когда они осуществляются не в теле основного потока (main), а путем многократного вызова функции, это может негативно сказаться на быстродействии скрипта.
 
Цитата
Иван Ру написал:
Цитата
nikolz написал:
 
Цитата
Иван Ру  написал:
Интересно мнение форумчан - как предпочитаете писать скрипты - все в одном файле или в виде конструктора - с подгрузкой отдельных файлов:
1. Отдельных функций/процедур (выставление заявки, считывание определенных данных и т.п.)
2. Отдельных классов (стратегия, позиция и т.п.)
 Существующая структура QLUA имеет существенный недостаток.
Все колбеки вызываются из одного потока и каждый из них повторяется в различных скриптах.
В итоге получается дублирование одних и тех же действий многократно.
Я устранил эту проблему и сделал механизм при котором колбеки в скриптах не повторяются,
а скрипты могут запускать функции друг у друга и получать данные из других скриптов..
-------------------------
В итоге не только повышается скорость, но и размер кода сокращается в десятки раз.
Признаться, все более склоняюсь в сторону такой модели, в первую очередь из-за разрастания скрипта и усложнения его логики из-за чего работа и модификация скрипта становится все более затруднительной...
Полагаю можно использовать такую структуру:
- базовый скрипт, который определяет статус сессии и агрегирует информацию из коллбэков
- описание классов (стратегия, позиция и т.п.)
- типовые универсальные модули, например, удаление устаревшей части данных таблиц (цены, бид аск и т.п.), ежедневное определение ключевых временных точек сессии в формате posix, визуализация и логгирование информации и т.п.
- собственно скрипты с описанием стратегий, логики определение сигналов на вход и выход и сопутствующих действий...

Если кто-то поделится своим видением организационной структуры - буду признателен

Поясню свое прежнее беспокойство - у меня большинство скриптов работает одновременно с большим числом инструментов, предполагается большой объем расчетов, опасаюсь, что в тех случаях когда они осуществляются не в теле основного потока (main), а путем многократного вызова функции, это может негативно сказаться на быстродействии скрипта.
Проблема усложняется тем, что разработчики не утруждают себя документацией по API к их библиотеке,
нигде не описывают интерфейс взаимодействия скриптов с терминалом на уровне API C for LUA.
На основе ответов основного разработчика QLUA(не будем показывать пальцем) ,  
по-моему мнению, схема взаимодействия скриптов с терминалом следующая:
-------------------------------
Каждый скрипт условно можно разделить на три части
1) действия вне колбеков и функции main - это отдельный поток и VM Lua
2) функция main каждого скрипта - это отдельный поток и VMLua
3) вызов и исполнение  функций колбек осуществляется  в одном основном потоке термина.
---------------------------
В итоге получаем следующее.
Если Вы не профессионал , то скорее всего будете много делать в колбеках  - так проще .
Все колбеки будете вызывать в каждом из скриптов.
-------------------------------
Получается прикольно.
Даже если у Вас суперкомпьютер с 128 ядрами , то все колбеки будут тупо работать на одном ядре и в одном потоке,
в котором крутится еще и основное ядро терминала КВИК.
------------------
Сейчас версию 7 заменяют на версию 8
В итоге XP с одним ядром не работает вообще. Но зато у Вас теперь win10 64 бита и ядер хоть 128.
А что реально в сухом остатке?
--------------------------
Представим что на телегу прикрутить двигатель от болида формулы 1, а впереди телеги все та же лошадь  .
Вопрос, насколько быстрее эта телега теперь довезет Вас из пункта А в пункт В?
-----------------------------------------
Конечно есть решение костыльное - ничего не делать в колбеках,  а делать все в main.
Но резонно спросить разработчиков, а о чем думали они когда разрабатывали концепцию встраиваемой виртуальной машины?
--------------------------------
Да и это костыльное решение не решает проблему многократного дублирования кода в различных скриптах.
---------------------------------
На самом деле все могло  быть существенно проще и исполняться существенно быстрее, но именно это никому не требуется.
--------------------------
На рынке всегда решается лишь одна задача, за разработку инструмента для решения которой платят разработчикам, -  как у буратины отобрать пять золотых.
-----------------------------------
В итоге для целей конструирование игрушечных роботов,
чем занимаются посетители данного форума,
все сделано просто замечательно.
============================================================­========================
"Теперь попросим на трибуну начальника транспортного цеха. Пусть доложит об изыскании внутренних резервов. "
 
 
Цитата
nikolz написал:
Каждый скрипт условно можно разделить на три части1) действия вне колбеков и функции main - это отдельный поток и VM Lua2) функция main каждого скрипта - это отдельный поток и VMLua3) вызов и исполнение  функций колбек осуществляется  в одном основном потоке термина.
Не совсем оно так, стейт для тела скрипта и колбеков один и выполняется в основном потоке квика, стейт для мейна второй и выполняется в специально для него созданном потоке. То есть ваш п.1 лишний, нет отдельного стейта для тела.

Ваши мысли насчет 128 ядер это из разряда давайте загрузим проц бесполезной работой, чо он простаивает-то. В любом случае ваши 100500 потоков будут сериализоваться на доступе к общим ресурсам, т.е. в основном (в таком количестве) они будут крутить спинлок. Для примера предлагаю прогу из directx sdk, где можно отрисовать одно и то же либо одним потоком, либо многими. Запустите и убедитесь, что проц оно жрет в N раз больше, а fps растет процентов на 5.
 
Это, конечно, похвально написать свой RabbitMQ, но, в результате, получится схема не меньшей сложности. Т.е. мы пишем свой терминал. Он будет собирать события терминала, исполнять команды скриптов и читать их ответы, передавать им поток данных.

При этом мы итак находимся внутри такого окружения... Что мешает написать скрипт исполняющий сразу несколько алгоритмов, по многим инструментам. Будет один скрипт, одно окружение.
А колбеки Квика слишком ненадежная конструкция. Проще без них. Хотя, конечно, от части из них отказаться сложно, как, например, OnTransReply.
 
Цитата
Anton написал:
Цитата
nikolz написал:
Каждый скрипт условно можно разделить на три части1) действия вне колбеков и функции main - это отдельный поток и VM Lua2) функция main каждого скрипта - это отдельный поток и VMLua3) вызов и исполнение  функций колбек осуществляется  в одном основном потоке термина.
Не совсем оно так, стейт для тела скрипта и колбеков один и выполняется в основном потоке квика, стейт для мейна второй и выполняется в специально для него созданном потоке. То есть ваш п.1 лишний, нет отдельного стейта для тела.

Ваши мысли насчет 128 ядер это из разряда давайте загрузим проц бесполезной работой, чо он простаивает-то. В любом случае ваши 100500 потоков будут сериализоваться на доступе к общим ресурсам, т.е. в основном (в таком количестве) они будут крутить спинлок. Для примера предлагаю прогу из directx sdk, где можно отрисовать одно и то же либо одним потоком, либо многими. Запустите и убедитесь, что проц оно жрет в N раз больше, а fps растет процентов на 5.
Я вам предлагаю для примера посмотреть алгоритм БПФ либо нейронной сети  
 
Цитата
Nikolay написал:
Это, конечно, похвально написать свой RabbitMQ, но, в результате, получится схема не меньшей сложности. Т.е. мы пишем свой терминал. Он будет собирать события терминала, исполнять команды скриптов и читать их ответы, передавать им поток данных.

При этом мы итак находимся внутри такого окружения... Что мешает написать скрипт исполняющий сразу несколько алгоритмов, по многим инструментам. Будет один скрипт, одно окружение.
А колбеки Квика слишком ненадежная конструкция. Проще без них. Хотя, конечно, от части из них отказаться сложно, как, например, OnTransReply.
вообще-то я написал о том, что сделал сам лет ...надцать назад,
т е фактически сразу как внедрили VMlua в квик.
А перед этим примерно года за два я сам в переписке с руководством разработчика предлагал внедрить вместо QPILE LUA.
не утверждаю, что они меня послушались, но в результате появился луа в квике.
---------------------
Тот механизм, о котором я написал, позволяет очень просто делать много роботов  по различным алгоритмом для одного инструмента.
Колбеки не дублируются в скриптах  
Каждый колбек существует в своем скрипте и вызывается всего один раз квиком для получения данных вне зависимости от числа роботов.
Роботы получают требуемые данные от этого скрипта. т е потоки синхронизируются и обмениваются данными , а также чтобы не дублировать код, могут запускать функции других скриптов через механизм колбеков между скриптами.
Сравнительно просто в этом варианте отдавать данные совершенно независимым процессам.
-----------------------
Но если не мечтать о вечном,
то проще всего делать роботов как индикаторы.
 
Ребята, вы о высоком, признаться я уже не все понимаю.
Если вернуться к реальности, где основная масса, включая меня - любители, а не профессионалы в программировании, и мы имеем, то что имеем, остаются интересные вопросы с потенциально возможными интересными ответами.

- Целесообразно ли минимизировать использование колбэков и как?
- Стоит ли писать общие классы-таблицы для роботов?
- Как конкретно оптимально подгружать универсальные функции...
И т.п. и т.д.
 
Цитата
nikolz написал:
Я вам предлагаю для примера посмотреть алгоритм БПФ либо нейронной сети
Не спорю, тяжелая вычислялка, пригодная для распараллеливания, от потоков выиграет. Но такое на луа писать несколько самонадеянно, даже и в виде длл. Если данные в виде луа-таблицы, мы больше потеряем на доступе к ней, тут нужны плейн массивы. В сухом остатке на долю луа остается периодически подбрасывать новые данные по мере их приезда с сервера, а для этого много потоков не нужно и даже вредно, сеть-то сама по себе труба в одну нитку. Равно и в обратную сторону, можно натыкать миллион транзакций и они встанут в очередь на сокете и ничего более. В данном случае асинхронность лучше многопоточности, а у этого подхода есть ограничительный фактор - целевая аудитория может ниасилить.
 
Цитата
Иван Ру написал:
- Целесообразно ли минимизировать использование колбэков и как?
Это вопрос архитектурный. Варианта два.

Первый - это event-driven архитектура, тут колбеки движущая сила всего, пришел колбек - это событие, вы это событие как-то обрабатываете, если обработка предполагает что-то тяжелое - вы только запускаете операцию и возвращаетесь из колбека, а о ее завершении вам сообщит другой колбек, уже ваш собственный.

Второй это поллинг, ваш мейн шаг за шагом следует какому-то плану. Где ему нужны какие-то данные, он их заказывает и ждет ответа, где нужно что-то отправить он отправляет и ждет ответа. Уже по описанию видно, насколько шустро оно будет работать, хотя есть, несомненно, задачи, в которых и так сойдет. Другой недостаток - вы видите какое-то событие только в тот момент, когда решили на него посмотреть, а оно может уже часа два как произошло. Например, пока вы считали что-то и готовили транзакцию, квик потерял соединение, но вы еще об этом не знаете и продолжаете готовиться к своей сделке века, которая закончится ничем, бо нет коннекта. Утрирую для наглядности.

Третий вариант это как тут часто в вопросах попадается, когда смешали все в кучу и получилась, естественно, куча.
 
Цитата
Anton написал:
Цитата
Иван Ру написал:
- Целесообразно ли минимизировать использование колбэков и как?
Это вопрос архитектурный. Варианта два.

Первый - это event-driven архитектура, тут колбеки движущая сила всего, пришел колбек - это событие, вы это событие как-то обрабатываете, если обработка предполагает что-то тяжелое - вы только запускаете операцию и возвращаетесь из колбека, а о ее завершении вам сообщит другой колбек, уже ваш собственный.

Второй это поллинг, ваш мейн шаг за шагом следует какому-то плану. Где ему нужны какие-то данные, он их заказывает и ждет ответа, где нужно что-то отправить он отправляет и ждет ответа. Уже по описанию видно, насколько шустро оно будет работать, хотя есть, несомненно, задачи, в которых и так сойдет. Другой недостаток - вы видите какое-то событие только в тот момент, когда решили на него посмотреть, а оно может уже часа два как произошло. Например, пока вы считали что-то и готовили транзакцию, квик потерял соединение, но вы еще об этом не знаете и продолжаете готовиться к своей сделке века, которая закончится ничем, бо нет коннекта. Утрирую для наглядности.

Третий вариант это как тут часто в вопросах попадается, когда смешали все в кучу и получилась, естественно, куча
Что касается этого аспекта - выбор я уже давно сделал в пользу второго варианта, коллбэки я либо не использую, либо они играют второстепенную роль. Колбэк я считаю вариантом не надежным (задержки, не сработал и т.п.), в то время как обработка в теле main позволяет не только получать данные, но и разные статусы, например, соединения нет, торгов нет, данные ни фига не получены, или они получены, но вряд ли актуальны. Картина получается куда полнее. С учетом того, что скорость транзакции у меня составляет порядка 150 мс, мне достаточно раз в 50 мс пробежаться по нужным параметрам в main, не вижу особого смысла в коллбэках разве только как в страховке или способе финальной верификации данных (о транзакции).
Меня больше интересует архитектура в плане разделения на модули и классы, степени их универсальности, способе подгрузки, компоновки рабочей стратегии из разных элементов конструктора.
 
Простой пример. Торгую я (вы) фьючерсами. Скрипт не трогаем, хотим чтобы он работал сам многие дни. Значит у нас периодически, желательно ежедневно, надо инициировать инструментов вплоть до выбора их корректного названия кода, на основе соответствующей таблицы из Квик, которая периодически меняется/обновляется.
У меня эта задача реализована так - в двух случаях, 1) при смене даты, 2) при проходе через временную точку 9 часов 40 минут вызывается функция инициализации инструментов-стратегий. Задача делается отчасти с помощью подгружаемого модуля, который сравнивает короткие коды инструментов, их календарный индекс с данными настроек стратегии в роботе.
Раньше вызов этих функций делал в OnInit и Main, теперь - только в main. Правда периодически случается что дата на сервере меняется после 10.00 !! По крайней мере такие данные прилетают...
Интересно, кто как решает типовые задачи, какую архитектуру при этом  использует. Например, чтение последней цены, бид-аск - в пределах main (быстрее) или вызовом отдельной функции. Ну ок, у вас отдельная функция, что функционально, пардон за тавтологию. Но если я читаю бид-аск 20 раз за секунду, по 10-ти инструментам, позволительно ли это делать в отдельной функции?
Все относительно, но все же - какое количество вызовов сторонней функции позволительно для ресурсов мощной машины на ваш взгляд (очень грубой оценки достаточно).
 
Цитата
Иван Ру написал:
Но если я читаю бид-аск 20 раз за секунду, по 10-ти инструментам, позволительно ли это делать в отдельной функции?
Вызов функции не то чтобы тяжелая операция. Грубо ориентировочно наброшу цифр.

Если функция находится в длл, луа перед ее вызовом снимает лок, а после - снова захватывает, это самая тяжелая часть вызова (самого по себе вызова, не тела функции). Пара EnterCriticalSection/LeaveCriticalSection занимает порядка 100нс, новее железо - меньше. Всем остальным оверхедом вызова в сравнении с этим можно пренебречь, т.е. время на порядок меньше. Ок, чтобы получить оверхед в одну секунду, надо сделать порядка 10 миллионов вызовов функций из длл в одном цикле без слипов и прочих ожиданий.

Если функция написана на луа, лок не выпускается и остается только то, чем мы выше пренебрегли. Предполагая разницу на один порядок, получим, что секундный оверхед будет достигнут на порядка 100 миллионах вызовов.

Резюме: вообще не о чем париться.
 
Любопытства ради небольшой тест, тксть поверим теорию практикой (вариант с длл писать лень)
Код
function add_global(a, b)
   return a + b
end

local function add_clocal(a, b)
   return a + b
end

function main()
   local count = 10000000
   local function toftime(a)
      local aa = a.hour
      aa = aa * 60
      aa = aa + a.min
      aa = aa * 60
      aa = aa + a.sec
      aa = aa * 1000000
      aa = aa + a.mcs
      return aa
   end
   local function add_flocal(a, b)
      return a + b
   end
   -- perform 'count' function-level function calls
   local sum = 0
   local tm = os.sysdate()
   for i = 0, count - 1 do
      sum = add_flocal(sum, i)
   end
   local tflevel = toftime(os.sysdate()) - toftime(tm)
   -- perfrom 'count' chunk-level function calls
   sum = 0
   tm = os.sysdate()
   for i = 0, count - 1 do
      sum = add_clocal(sum, i)
   end
   local tclevel = toftime(os.sysdate()) - toftime(tm)
   -- perform 'count' global function calls
   sum = 0
   tm = os.sysdate()
   for i = 0, count - 1 do
      sum = add_global(sum, i)
   end
   local tglobal = toftime(os.sysdate()) - toftime(tm)   
   -- perform 'count' inlined pseudocalls
   sum = 0
   tm = os.sysdate()
   for i = 0, count - 1 do
      sum = sum + i
   end
   local tinline = toftime(os.sysdate()) - toftime(tm)
   -- show results
   message("Function call overheads:\n" ..
      "  function-level function: " .. (tflevel - tinline) / count .. "us\n" ..
      "  chunk-level function   : " .. (tclevel - tinline) / count .. "us\n" ..
      "  global function:       : " .. (tglobal - tinline) / count .. "us\n")
end
Страницы: 1
Читают тему (гостей: 1)
Наверх