Деплоим TwinCAT 3.1
В TwinCAT ADS (ихнее byte-API) есть т.н. SUMUP-запросы, которые позволяют делать балк-операции. Например, записать значения сразу в несколько переменных PLC, или наоборот - считать. Надо сказать, что переменные обычно для красоты оперируются не именами, а handles - аналог file handles, и чтобы создать эти хендлы балком, мы посылаем SUMUP read/write запрос на специальный сервисный регистр, в который пишутся имена переменных, а читаются соответственно выделенные хендлы. Та же операция применяется чтобы быстро опросить типы и свойства переменных - пишем в другой регистр названия переменных, а буфер результата заполняется информацей.
Всё это красиво работает, когда ADS поднято на конкретном PLC. Но на TwinCAT-машине еще есть device-ADS-server, который отдает глобальные пременные, которыми оперируют все PLC-процессы на машине. Так вот, ВНЕЗАПНО, read-bulks на нем работают отлично. А вот write-bulks и read-write-bulks - нет. Соответственно, исходя из первого абзаца, не работают не только bulk writes значений переменных, но и сервисные операции - открытие хендлов, опрос типов переменных и прочее-подобное.
Делаем запрос в Beckhoff - мол, какого хуя
Получаем официальный ответ - это не бага, а фича. ебитесь как хотите. разбивайте мол балк-запросы на клиенте и посылайте по одному, например. шо вы к нам пристаете?
Причем те же люди, которые настаивали на использовании балков.
Вот такой вот индастриал-ентерпрайз. Кровавый и жестокий.
В TwinCAT ADS (ихнее byte-API) есть т.н. SUMUP-запросы, которые позволяют делать балк-операции. Например, записать значения сразу в несколько переменных PLC, или наоборот - считать. Надо сказать, что переменные обычно для красоты оперируются не именами, а handles - аналог file handles, и чтобы создать эти хендлы балком, мы посылаем SUMUP read/write запрос на специальный сервисный регистр, в который пишутся имена переменных, а читаются соответственно выделенные хендлы. Та же операция применяется чтобы быстро опросить типы и свойства переменных - пишем в другой регистр названия переменных, а буфер результата заполняется информацей.
Всё это красиво работает, когда ADS поднято на конкретном PLC. Но на TwinCAT-машине еще есть device-ADS-server, который отдает глобальные пременные, которыми оперируют все PLC-процессы на машине. Так вот, ВНЕЗАПНО, read-bulks на нем работают отлично. А вот write-bulks и read-write-bulks - нет. Соответственно, исходя из первого абзаца, не работают не только bulk writes значений переменных, но и сервисные операции - открытие хендлов, опрос типов переменных и прочее-подобное.
Делаем запрос в Beckhoff - мол, какого хуя
Получаем официальный ответ - это не бага, а фича. ебитесь как хотите. разбивайте мол балк-запросы на клиенте и посылайте по одному, например. шо вы к нам пристаете?
Причем те же люди, которые настаивали на использовании балков.
Вот такой вот индастриал-ентерпрайз. Кровавый и жестокий.
👍6😁5
Следующий сюрприз, который ждет вас с TwinCAT - ADS over TCP/IP не поддерживает больше одного соединения с одной машины.
Да, просто не поддерживает. Это правило и его менять нельзя. А как же AMS-роутинг и всё такое? А вот по одному сокету и роутинг. Подключите второй - первый сразу же вывалится.
А как же быть, если два приложения, которые опрашивают например два разных PLC? https://github.com/Beckhoff/ADS/issues/49 - тут небольшой срач и workarounds. Народ предлагает цеплять два IP и делать костыли в iptables. Ну или купите себе две машины, раз у вас есть деньги на TwinCAT.
В EVA ICS v4 мы пошли иначе и гейтуем ADS с нашей шиной через byte-payloads. Таким образом, мост-прокся работает без лишних overhead с промежуточным парсингом данных, а локальные сервисы и приложения могут дергать любые ADS-регистры на любых TwinCAT-устройствах по своему усмотрению, в том числе сами оперировать с handles. Кстати, до релиза меньше месяца.
p.s. да, получил еще один интересный емейл, просят не злоупотреблять опросом регистров, так как "TCP/IP сильно влияет на jitter реалтайм-приложений". Ну если реалтайм делать на винде, то какие могут быть вопросы. Винда ведь известная риалтайм-платформа. Дайте мне 200 миллионов и я выкуплю у ежевик QNX обратно.
Да, просто не поддерживает. Это правило и его менять нельзя. А как же AMS-роутинг и всё такое? А вот по одному сокету и роутинг. Подключите второй - первый сразу же вывалится.
А как же быть, если два приложения, которые опрашивают например два разных PLC? https://github.com/Beckhoff/ADS/issues/49 - тут небольшой срач и workarounds. Народ предлагает цеплять два IP и делать костыли в iptables. Ну или купите себе две машины, раз у вас есть деньги на TwinCAT.
В EVA ICS v4 мы пошли иначе и гейтуем ADS с нашей шиной через byte-payloads. Таким образом, мост-прокся работает без лишних overhead с промежуточным парсингом данных, а локальные сервисы и приложения могут дергать любые ADS-регистры на любых TwinCAT-устройствах по своему усмотрению, в том числе сами оперировать с handles. Кстати, до релиза меньше месяца.
p.s. да, получил еще один интересный емейл, просят не злоупотреблять опросом регистров, так как "TCP/IP сильно влияет на jitter реалтайм-приложений". Ну если реалтайм делать на винде, то какие могут быть вопросы. Винда ведь известная риалтайм-платформа. Дайте мне 200 миллионов и я выкуплю у ежевик QNX обратно.
GitHub
Multiple connections to a single TwinCAT computer. · Issue #49 · Beckhoff/ADS
Hi, I'm having trouble connecting multiple instances of the same AdsLib application to a single TwinCat computer. Program instance 1. AdsAddRoute AdsPortOpenEx while(1) { read/write some data o...
👍5🔥3😁2
Кстати про BMS. Некоторым участникам рынка надоело, что существует 10500 протоколов домашнего оборудования.
Поэтому был образован новый, открытый стандарт, который конечно же заменит все существующие: https://csa-iot.org/ и наконец заживём.
Как это работает на практике с любым стандартом: делаем новый стандарт с альянсом и настойчиво предлагаем какому-нибудь Siemens членство и коньяк бесплатно
- а теперь вступайте в наш новый альянс!
- нахера он нам нужен?
- он заменит бляблябля, а ещё с нами Siemens
- отлично, берите нас тоже
- с вас десять тыщ в год
Поэтому был образован новый, открытый стандарт, который конечно же заменит все существующие: https://csa-iot.org/ и наконец заживём.
Как это работает на практике с любым стандартом: делаем новый стандарт с альянсом и настойчиво предлагаем какому-нибудь Siemens членство и коньяк бесплатно
- а теперь вступайте в наш новый альянс!
- нахера он нам нужен?
- он заменит бляблябля, а ещё с нами Siemens
- отлично, берите нас тоже
- с вас десять тыщ в год
CSA-IOT
We are leading the movement to enable all objects to simply, securely, and seamlessly connect the world around you. Become A Member The Connectivity Standards Alliance is the place where industry…
😁9💩2👍1
Rust + clippy дают просто сумасшедшие возможности для рефакторинга. В Rust-код можно вгрызаться в любом виде и если ворнингов нету, быть на 99,9% уверенным, что ничего не сломалось.
Первый рефакторинг я начинаю ещё до релиза. Заметил, что часто пишу новые приложение в один-два модуля с длинными функциями, совершенно не планируя архитектуру. Когда код готов - думаю, как лучше разделить функционал и начинаю разбивку, которая занимает совсем немного времени и обычно совершенно безопасна.
В любом другом языке я бы так не просто не смог, я бы даже не посмел.
Первый рефакторинг я начинаю ещё до релиза. Заметил, что часто пишу новые приложение в один-два модуля с длинными функциями, совершенно не планируя архитектуру. Когда код готов - думаю, как лучше разделить функционал и начинаю разбивку, которая занимает совсем немного времени и обычно совершенно безопасна.
В любом другом языке я бы так не просто не смог, я бы даже не посмел.
🔥15👍7👎2💩1
Раз теперь наконец есть open-source компилятор StructuredText, еще и на Rust, продолжаю с ним играться.
Давайте рассмотрим небольшой пример PLC-программы: есть два mapped-регистра reg1 и reg2 и глобальная переменная counter. Мы будем использовать стандартный таймер IEC 61131-3 и прибавлять к counter оба регистра каждую секунду.
Напишем простой PLC на Rust. В реальном мире reg1 и reg2 будут мапиться куда-то, например на GPIO или может на внешнее Modbus-устройство, но в примере мы просто присвоим им статические значения. "Стек" для PLC-программы выделим одним блоком.
Давайте рассмотрим небольшой пример PLC-программы: есть два mapped-регистра reg1 и reg2 и глобальная переменная counter. Мы будем использовать стандартный таймер IEC 61131-3 и прибавлять к counter оба регистра каждую секунду.
VAR_GLOBALПоскольку TON - не стандартный объект ST, а объект IEC 61131-3, нам будет необходима библа libiec61131std.so, которую пацаны из проекта PLC lang тоже полностью написали на Rust. Компилируем нашу ST-программу, в этом примере консольным компилятором и получаем shared-библу prog.so:
counter, reg1, reg2: DINT;
END_VAR
PROGRAM hello
VAR
timer: TON; t_out: BOOL; t_et: TIME;
END_VAR
timer(IN := NOT(t_out), PT := t#1s, Q => t_out, ET => t_et);
IF timer.Q THEN
counter := counter + reg1 + reg2;
END_IF
END_PROGRAM
rustyc --shared prog.st timers.st -L$(pwd) -liec61131stdЧто такое PLC-программа? В миру это - обычная функция, с одним нюансом: все локальные переменные она пишет не в стек, а в некую внешнюю область памяти, что позволяет использовать их значения повторно, когда программа вызывается в цикле. PLC, в свою очередь, может между циклами этой областью управлять, например выводя переменные для отладки или просто периодически сохраняя всю область на внешнюю карту памяти.
Напишем простой PLC на Rust. В реальном мире reg1 и reg2 будут мапиться куда-то, например на GPIO или может на внешнее Modbus-устройство, но в примере мы просто присвоим им статические значения. "Стек" для PLC-программы выделим одним блоком.
fn main() {Если мы запустим пример, каждую секунду счётчик программы будет увеличиваться на 3. Следующий этап рисерча - автоматически определять размер "стека". Поскольку rusty может генерить промежуточный LLVM IR, копаю в этом направлении.
unsafe {
let mut stack = vec![0; 4096];
let lib = libloading::Library::new("prog.so").unwrap();
let program: libloading::Symbol<fn(&mut [u8])> = lib.get(b"hello").unwrap();
let counter: libloading::Symbol<*mut i32> = lib.get(b"counter").unwrap();
let reg1: libloading::Symbol<*mut i32> = lib.get(b"reg1").unwrap();
let reg2: libloading::Symbol<*mut i32> = lib.get(b"reg2").unwrap();
**reg1 = 1;
**reg2 = 2;
loop {
program(&mut stack);
dbg!(**counter);
}
}
}
👍7
По техдокументации скажу пару слов. Не по автохелперам для библиотек и модулей, которые дергаются из комментов функций, а по product documentation.
В былинные времена, лет 20 назад, работал я в одной конторе, и у нас там на 30 человек персонала было целых три техрайтера, которые целыми днями ебли наш корпоративный Typo3, а в перерывах - учили нас английскому. Надо сказать, что 2 из 3 со временем стали сами программерами, а третий уволился. Так мы остались без техрайтеров и постепенно стали писать доки сами, силами бывших и собственными.
Что могу заметить по английскому. Если вы не можете взять грамотного техрайтера - не берите. Не берите всех этих переводчиков, "преподавателей" (в кавычках), не берите native speakers, только потому что они native speakers и прочих тоже не берите. Техническая документация - это отдельная специальная олимпиада, со своими особенностями (например: само собой недопускаются contractions, недопускаются местоимения, зато наоборот - допускаются приемы из журналистики, например CamelCases в заголовках) и в этой олимиаде должны участвовать профи. Идеально конечно, если руководитель проекта может сам написать к нему документацию, иначе придётся всё равно тратить уйму времени и учить техрайтера проекту.
По форматам. Всё что не RST и Markdown - сразу лесом. Во-первых, техдокументация должна легко генериться скриптами, там где она может генериться, а не копи-пастаться в какой-то вебморде. Во-вторых, в техдокументации, как и во всём остальном, важно не иметь vendor lock-in и легко сбежать при надобности.
Конкретно хинты по RST - всегда ставьте метки вида product+метка, а не просто метка. Иначе при объединении нескольких продуктов в один получите адок. Тоже самое по ссылкам - никогда не ставьте абсолютные. Никто не знает, куда вашу документацию захочется всунуть через 5 лет и с какой структурой.
По движкам. Я люблю Sphinx. По простой причине - я хорошо знаю Sphinx, писал под него плагины, пара даже стали популярными. Единственный, но большой недостаток Sphinx - у него ужасный стандартный поиск.
В былинные времена, лет 20 назад, работал я в одной конторе, и у нас там на 30 человек персонала было целых три техрайтера, которые целыми днями ебли наш корпоративный Typo3, а в перерывах - учили нас английскому. Надо сказать, что 2 из 3 со временем стали сами программерами, а третий уволился. Так мы остались без техрайтеров и постепенно стали писать доки сами, силами бывших и собственными.
Что могу заметить по английскому. Если вы не можете взять грамотного техрайтера - не берите. Не берите всех этих переводчиков, "преподавателей" (в кавычках), не берите native speakers, только потому что они native speakers и прочих тоже не берите. Техническая документация - это отдельная специальная олимпиада, со своими особенностями (например: само собой недопускаются contractions, недопускаются местоимения, зато наоборот - допускаются приемы из журналистики, например CamelCases в заголовках) и в этой олимиаде должны участвовать профи. Идеально конечно, если руководитель проекта может сам написать к нему документацию, иначе придётся всё равно тратить уйму времени и учить техрайтера проекту.
По форматам. Всё что не RST и Markdown - сразу лесом. Во-первых, техдокументация должна легко генериться скриптами, там где она может генериться, а не копи-пастаться в какой-то вебморде. Во-вторых, в техдокументации, как и во всём остальном, важно не иметь vendor lock-in и легко сбежать при надобности.
Конкретно хинты по RST - всегда ставьте метки вида product+метка, а не просто метка. Иначе при объединении нескольких продуктов в один получите адок. Тоже самое по ссылкам - никогда не ставьте абсолютные. Никто не знает, куда вашу документацию захочется всунуть через 5 лет и с какой структурой.
По движкам. Я люблю Sphinx. По простой причине - я хорошо знаю Sphinx, писал под него плагины, пара даже стали популярными. Единственный, но большой недостаток Sphinx - у него ужасный стандартный поиск.
👍20🔥2
Я еще не проходился по OPC UA. Давайте начнем с небольшой преамбулы
Подход к структурам данных автоматизированных систем условно можно разделить на три группы:
- Прямое управление памятью (контекстом). Мы читаем-пишем регистры по их указателю, у регистров могут быть типы, всё структурирование происходит на стороне клиента. За примером далеко ходить не надо: Modbus. Два типа регистров, bit и word (16-bit), а дальше возитесь как хотите.
- Частичное структурирование. Мы читаем-пишем регистры по некоему пути struct.field.subfield.value, у регистров могут быть четкие типы (SNMP) или типами опять же занимается клиент (эти ваши MQTT payloads). Но структура не может явно иметь enums, не может иметь массивы (SNMP может, но сколько там в один OID chunk влазит? 65536? Вот с этим и работайте).
- Полное структурирование. Данные представляются в том виде, в котором их может представлять программа (т.е. в любом)
В чем идея OPC UA? Теория отличная - давайте сделаем сервер с полным структурированием данных и со строгой типизацией, который будет промышленным стандартом, универсальным, мощным и закрепленным на века.
Теперь практика.
Ноги OPC UA растут из OPC, который появился в начале 90х благодаря усилиям Rockwell и еще пары компаний и полностью базировался на COM/DCOM. Не смотря на всю открытость, сын гордого предка так и не смог избавиться от запашка той "старой" винды, со всеми вытекающими.
В OPC UA Foundation сейчас около 30 крупных компаний, которые лепят стандарт под себя уже почти 30 лет. Последствия немного предсказуемы - стандарт превратился в монстра, который включает в себя огромное API, с авторизацией клиентов и без, функции TSDB, логики алярмов и ивентов, а в 2018 году Foundation дополнительно договорились, что гейтовать на сторонние Pub/Sub - несерьезно, и сделали свой. Каждый OPC UA-сервер обязательно включает в себя талмуд, какие функции стандарта реализованы, а какие - не очень. Подозреваю, что в Foundation нет пожалуй ни одного мембера, который бы имплементировал всё до буквы.
Входной билет в OPC UA - это тонны онлайн-спецификаций, IEC 62541 и пара редких книг по 400 страниц, цена которых сегодня приближается к 100$. Стандарт родился замороченным, а через десятки лет "улучшений" стал замороченным еще более.
Результат? Инженеры боятся OPC UA, за 10 лет я видел только несколько контроллеров от Phoenix Contact, которые не давали ничего кроме, а внедрение сравнимо с внедрением SAP - к серверу обязательно пригалается в коробке инженер или несколько.
Последний месяц занимаюсь тем, с чего начинался OPC UA - динамическим контекстом с полным структурированием данных и более-менее строгой типизацией. Работа не срочная, поэтому поставил себе цель - не просто освежить знания по OPC UA, а выучить стандарт максимально полностью, чтобы не изобретать чужие велосипеды и не вставлять чужие грабли. Но боюсь, через пару месяцев заберут в дурку.
Подход к структурам данных автоматизированных систем условно можно разделить на три группы:
- Прямое управление памятью (контекстом). Мы читаем-пишем регистры по их указателю, у регистров могут быть типы, всё структурирование происходит на стороне клиента. За примером далеко ходить не надо: Modbus. Два типа регистров, bit и word (16-bit), а дальше возитесь как хотите.
- Частичное структурирование. Мы читаем-пишем регистры по некоему пути struct.field.subfield.value, у регистров могут быть четкие типы (SNMP) или типами опять же занимается клиент (эти ваши MQTT payloads). Но структура не может явно иметь enums, не может иметь массивы (SNMP может, но сколько там в один OID chunk влазит? 65536? Вот с этим и работайте).
- Полное структурирование. Данные представляются в том виде, в котором их может представлять программа (т.е. в любом)
В чем идея OPC UA? Теория отличная - давайте сделаем сервер с полным структурированием данных и со строгой типизацией, который будет промышленным стандартом, универсальным, мощным и закрепленным на века.
Теперь практика.
Ноги OPC UA растут из OPC, который появился в начале 90х благодаря усилиям Rockwell и еще пары компаний и полностью базировался на COM/DCOM. Не смотря на всю открытость, сын гордого предка так и не смог избавиться от запашка той "старой" винды, со всеми вытекающими.
В OPC UA Foundation сейчас около 30 крупных компаний, которые лепят стандарт под себя уже почти 30 лет. Последствия немного предсказуемы - стандарт превратился в монстра, который включает в себя огромное API, с авторизацией клиентов и без, функции TSDB, логики алярмов и ивентов, а в 2018 году Foundation дополнительно договорились, что гейтовать на сторонние Pub/Sub - несерьезно, и сделали свой. Каждый OPC UA-сервер обязательно включает в себя талмуд, какие функции стандарта реализованы, а какие - не очень. Подозреваю, что в Foundation нет пожалуй ни одного мембера, который бы имплементировал всё до буквы.
Входной билет в OPC UA - это тонны онлайн-спецификаций, IEC 62541 и пара редких книг по 400 страниц, цена которых сегодня приближается к 100$. Стандарт родился замороченным, а через десятки лет "улучшений" стал замороченным еще более.
Результат? Инженеры боятся OPC UA, за 10 лет я видел только несколько контроллеров от Phoenix Contact, которые не давали ничего кроме, а внедрение сравнимо с внедрением SAP - к серверу обязательно пригалается в коробке инженер или несколько.
Последний месяц занимаюсь тем, с чего начинался OPC UA - динамическим контекстом с полным структурированием данных и более-менее строгой типизацией. Работа не срочная, поэтому поставил себе цель - не просто освежить знания по OPC UA, а выучить стандарт максимально полностью, чтобы не изобретать чужие велосипеды и не вставлять чужие грабли. Но боюсь, через пару месяцев заберут в дурку.
👍16
TSDB хороши, когда вам надо сделать умный дом и мониторить температуру в туалете. Когда же доходит до практического применения в промышленных приложениях, все сразу сходят с дистанции.
Если у вас один датчик, телеметрию можно спокойно снимать каждые условно 5 секунд и складывать в базу. После чего любой сможет запросить оттуда данные, подготовить, пересобрать, посчитать avg и плюнуть на график - тут достаточно даже SQL, а все эти модные TS-примочки только немного облегчают жизнь.
Если у вас сотня тысяч датчиков, причем данные нужно еще реплицировать на десяток других узлов - вы не можете хранить регулярную телеметрию и приходится переходить на event-based записи. И тут начинается веселье.
Ни одна популярная TSDB не может решить элементарный пример. Допустим, есть телеметрия:
00:00:58 - 2
00:01:20 - 10
и необходимо вывести минутные avg для 00:01:00-00:03:00.
Как только писаки TSDB слышат про иррегулярные данные, тут же везде включается одна и та же песня "ета слооожнаааа" и предлагается, в данном варианте например, построить промежуточный посекундный датафрейм, растянув данные по last, а затем уже считать avg. Не знаю как там где, а у нас один человек вылетел за такую идею с работы (это правда была последняя капля, но всё же), потому что last по минуте конечно хорошо, а вот для last по кварталу уже может даже не хватить даже памяти.
В общем, вернемся к реальным результатам. Во-первых ни одна сволочь не примет из коробки, что на 00:01:00 значение датчика было 2, это нужно делать неким промежуточным select(last) where time<00:01:00 руками. А раз руками - вся из-коробка уже вам ничем не поможет. Но, допустим, мы чудом построили руками (или он у нас был изначально) датафрейм
00:01:00 - 2
00:01:20 - 10
и применяем на него avg c fill 1m. Результат будет конечно же 6. Ну (10+2)/2 ведь 6, я понимаю. Но вы же time series или кто? Вы должны уметь нормально работать с временем. Потому что результат, мать вашу, будет не 6 и не 8. А (2*20+10*40)/60 = 7.333(3). Именно это я и любой другой вменяемый человек хотим видеть потом на графике. А, когда мы видим 6, хочется взять и уебать. Нет, мы можем конечно вернуться к идее не считать всё по формулам, а просто построить промежуточный датафрейм. И TSDB покажет нам наши 7 и 1/3. Но мы не можем и не хотим.
Итог: если у вас иррегулярные данные, все доступные TSDB подходят только для хранения логов, так что можете смело перейти для этого на любую обычную RDB. А дальше - упражняйтесь в математике сами. Они за вас не могут, им сложно. А мир всё дальше погружается в идиократию.
Если у вас один датчик, телеметрию можно спокойно снимать каждые условно 5 секунд и складывать в базу. После чего любой сможет запросить оттуда данные, подготовить, пересобрать, посчитать avg и плюнуть на график - тут достаточно даже SQL, а все эти модные TS-примочки только немного облегчают жизнь.
Если у вас сотня тысяч датчиков, причем данные нужно еще реплицировать на десяток других узлов - вы не можете хранить регулярную телеметрию и приходится переходить на event-based записи. И тут начинается веселье.
Ни одна популярная TSDB не может решить элементарный пример. Допустим, есть телеметрия:
00:00:58 - 2
00:01:20 - 10
и необходимо вывести минутные avg для 00:01:00-00:03:00.
Как только писаки TSDB слышат про иррегулярные данные, тут же везде включается одна и та же песня "ета слооожнаааа" и предлагается, в данном варианте например, построить промежуточный посекундный датафрейм, растянув данные по last, а затем уже считать avg. Не знаю как там где, а у нас один человек вылетел за такую идею с работы (это правда была последняя капля, но всё же), потому что last по минуте конечно хорошо, а вот для last по кварталу уже может даже не хватить даже памяти.
В общем, вернемся к реальным результатам. Во-первых ни одна сволочь не примет из коробки, что на 00:01:00 значение датчика было 2, это нужно делать неким промежуточным select(last) where time<00:01:00 руками. А раз руками - вся из-коробка уже вам ничем не поможет. Но, допустим, мы чудом построили руками (или он у нас был изначально) датафрейм
00:01:00 - 2
00:01:20 - 10
и применяем на него avg c fill 1m. Результат будет конечно же 6. Ну (10+2)/2 ведь 6, я понимаю. Но вы же time series или кто? Вы должны уметь нормально работать с временем. Потому что результат, мать вашу, будет не 6 и не 8. А (2*20+10*40)/60 = 7.333(3). Именно это я и любой другой вменяемый человек хотим видеть потом на графике. А, когда мы видим 6, хочется взять и уебать. Нет, мы можем конечно вернуться к идее не считать всё по формулам, а просто построить промежуточный датафрейм. И TSDB покажет нам наши 7 и 1/3. Но мы не можем и не хотим.
Итог: если у вас иррегулярные данные, все доступные TSDB подходят только для хранения логов, так что можете смело перейти для этого на любую обычную RDB. А дальше - упражняйтесь в математике сами. Они за вас не могут, им сложно. А мир всё дальше погружается в идиократию.
👍20🔥4👎1😁1
Питон люди не любят не только потому что он медленно дробит, а еще и потому что всегда тянет кучу зависимостей.
Тем не менее, с зависимостями бороться довольно просто
1) не используйте зависимости, там где не нужно. чтобы прочитать конфиг, rapid-json вам не нужен
2) с момента как venv довели до ума, проблем с зависимостями нет в принципе. особенно если у вас стандартная архитектура и можно ставить бинарные пакеты
Не смотря на всё перечисленное, каждый месяц приходит письмо: "ваш питон-модуль не работает в моей наркоконде, она его не может собрать! помогите!". Причем в конверте только письмо, а денег нет.
Тем не менее, с зависимостями бороться довольно просто
1) не используйте зависимости, там где не нужно. чтобы прочитать конфиг, rapid-json вам не нужен
2) с момента как venv довели до ума, проблем с зависимостями нет в принципе. особенно если у вас стандартная архитектура и можно ставить бинарные пакеты
Не смотря на всё перечисленное, каждый месяц приходит письмо: "ваш питон-модуль не работает в моей наркоконде, она его не может собрать! помогите!". Причем в конверте только письмо, а денег нет.
😁20👍8💩3
Я на текущем проекте как-то незаметно стал фанатом SQLite и пихаю его куда нужно и не нужно
Несколько фактов:
- Если у вас сложная структура данных и клиент-сервер - SQLite конечно "смешная" БД. Но если вам нужно что-то компактное и встраиваемое, да еще и с практически полноценным SQL, а клиент-сервер не нужен или вы его реализуете сами - SQLite один из немногих выборов того, что вообще есть
- С топовыми настройками schema.synchronous и/или WAL, SQLite становится слегка задумчивой, зато совершенно неубиваемой, что важно для микрокомпьютеров в щитках, которые любят выключать рубильником
- Из коробки дает неплохую скорость, а засчёт ембеда может обгонять клиент-серверных собратьев на некоторых задачах в разы
- Данные пишутся очень компактно. INTEGER может быть от 0 до 8 байт, по обстоятельствам. Я сейчас смотрю на базу, в которой 102 млн записей в таблицах INT-INT-INT-REAL и это занимает 2.7 гига - тоесть в среднем по 26 байт на строку, и еще к этому умудрилось вместить в себя пару автоиндексов
В общем, древняя, проверенная временем база, биндинги под все популярные языки, куча клиентов чтобы распаковать данные, если ваша программа сдохла или чего-то не умеет. Если нужна просто мощная "хранилка" данных, а логику вы пишете сверху - почти без альтернатив.
Несколько фактов:
- Если у вас сложная структура данных и клиент-сервер - SQLite конечно "смешная" БД. Но если вам нужно что-то компактное и встраиваемое, да еще и с практически полноценным SQL, а клиент-сервер не нужен или вы его реализуете сами - SQLite один из немногих выборов того, что вообще есть
- С топовыми настройками schema.synchronous и/или WAL, SQLite становится слегка задумчивой, зато совершенно неубиваемой, что важно для микрокомпьютеров в щитках, которые любят выключать рубильником
- Из коробки дает неплохую скорость, а засчёт ембеда может обгонять клиент-серверных собратьев на некоторых задачах в разы
- Данные пишутся очень компактно. INTEGER может быть от 0 до 8 байт, по обстоятельствам. Я сейчас смотрю на базу, в которой 102 млн записей в таблицах INT-INT-INT-REAL и это занимает 2.7 гига - тоесть в среднем по 26 байт на строку, и еще к этому умудрилось вместить в себя пару автоиндексов
В общем, древняя, проверенная временем база, биндинги под все популярные языки, куча клиентов чтобы распаковать данные, если ваша программа сдохла или чего-то не умеет. Если нужна просто мощная "хранилка" данных, а логику вы пишете сверху - почти без альтернатив.
👍30🔥2💩1
Интересную багу сегодня выловил в WASM - при определенных обстоятельствах растовская thread-local RefCell::borrow_mut крашается прямо на функции с already borrowed: BorrowMutError
Похоже есть некоторый шанс, что wasm engine запустит ваш код в нескольких потоках, при этом thread-local переменные будут доступны во всех сразу
Браузеры, что с них взять...
Похоже есть некоторый шанс, что wasm engine запустит ваш код в нескольких потоках, при этом thread-local переменные будут доступны во всех сразу
Браузеры, что с них взять...
👍6💩2😁1
Вышел Rust 1.64. Из основного три фишки в двух словах:
- стабилизировали IntoFuture. тоесть структуру теперь можно конвертировать в Future не через жопу, а из коробки. например let req = DbRequest::new("select 1"); req.await;
- rust-analyzer наконец вошел в поставку. теперь для установки достаточно rustup component add rust-analyzer
- workspace получили секции workspace.package и workspace.dependencies. которые шарятся по всем мемберам воркспейса. ура
- стабилизировали IntoFuture. тоесть структуру теперь можно конвертировать в Future не через жопу, а из коробки. например let req = DbRequest::new("select 1"); req.await;
- rust-analyzer наконец вошел в поставку. теперь для установки достаточно rustup component add rust-analyzer
- workspace получили секции workspace.package и workspace.dependencies. которые шарятся по всем мемберам воркспейса. ура
👍14🔥2💩1
SQLite и скорость INSERT.
Последнюю объемную статью про Rust и SQLite я нашел датированную 2021 годом. Что изменилось с тех пор?
- асинхронный sqlx::sqlite стал намного шустрее и уже не проигрывает синхроному rusqlite
- bulk inserts по-прежнему самый быстрый метод вставки. Примерно 200k/sec в режиме транзакция-вставки-commit против 2,5-3mln/sec при bulk insert.
Биндить переменные или сразу вставлять в statement - разницы для скорости особой нет (в первом случае можете столкнуться с SQLITE_MAX_VARIABLE_NUMBER, во втором, если у вас числа - инжект, само собой, не словите). Разбивать на несколько или вставлять одним куском - в принципе тоже, если у вас конечно не специфический embed, где экономится каждый килобайт оперативки. Строку запроса лучше делать так:
3 миллиона инсертов в секунду, причем с sychronous=normal - это уже хорошие числа. Я доволен.
Последнюю объемную статью про Rust и SQLite я нашел датированную 2021 годом. Что изменилось с тех пор?
- асинхронный sqlx::sqlite стал намного шустрее и уже не проигрывает синхроному rusqlite
- bulk inserts по-прежнему самый быстрый метод вставки. Примерно 200k/sec в режиме транзакция-вставки-commit против 2,5-3mln/sec при bulk insert.
Биндить переменные или сразу вставлять в statement - разницы для скорости особой нет (в первом случае можете столкнуться с SQLITE_MAX_VARIABLE_NUMBER, во втором, если у вас числа - инжект, само собой, не словите). Разбивать на несколько или вставлять одним куском - в принципе тоже, если у вас конечно не специфический embed, где экономится каждый килобайт оперативки. Строку запроса лучше делать так:
let mut q = "INSERT INTO test VALUES ".to_owned();"дописывая" в строку записи в цикле, bottleneck будет уже на стороне Раста.
let mut vals = Vec::with_capacity(data.len());
for d in data { vals.push(format!("({},{})", d.0, d.1)); }
write!(q, "{}", vals.join(","));
3 миллиона инсертов в секунду, причем с sychronous=normal - это уже хорошие числа. Я доволен.
👍13🔥2
Клуб эникейщиков и 1С-программистов на нашем канале
Нужда довела до того, что при появлении полосок на сканированных документах, вместо того чтобы купить новый сканер, пришлось почистить старый
На слайде отмечен сканер автоподатчика, там иногда собирается всякая всячина, особенно если подписывали гелевой ручкой. Всё это чистится спиртом (наружно)
Нужда довела до того, что при появлении полосок на сканированных документах, вместо того чтобы купить новый сканер, пришлось почистить старый
На слайде отмечен сканер автоподатчика, там иногда собирается всякая всячина, особенно если подписывали гелевой ручкой. Всё это чистится спиртом (наружно)
👍6😁5
😁17👍1💩1
Насчёт языков такой пример приведу.
Я люблю писать движки для сайтов сам, потому что в движок вставляю кучу логики. Даже если сайт генерится полностью статиком (кто не вставляет - есть https://www.getzola.org)
Что заметил. Любой такой движок всегда начинается с "это же херня, там надо только шаблоны, ебнем jinja (tera) и поехали. Скрипт на баше справится". Через пару дней вставляется первая логика, через неделю верстка хочет минифаеры (и вставляется какое-то унылое говно на nodejs в обертке от питономодуля), через месяц "движок" выглядит так, что туда смотреть не хочется. Работает и хорошо. А если нет - хрен поймешь, что случилось, так что лучше уже не трогать.
В отличие от движков на Rust. Такие движки почему-то всегда в порядке. Их показывают джунам, как примеры кода. Их элементарно расширять, им не надо тащить говно с npmjs - комьюнити врапперы для говна не принимает.
Так что мой выбор - как бы очевиден.
Я люблю писать движки для сайтов сам, потому что в движок вставляю кучу логики. Даже если сайт генерится полностью статиком (кто не вставляет - есть https://www.getzola.org)
Что заметил. Любой такой движок всегда начинается с "это же херня, там надо только шаблоны, ебнем jinja (tera) и поехали. Скрипт на баше справится". Через пару дней вставляется первая логика, через неделю верстка хочет минифаеры (и вставляется какое-то унылое говно на nodejs в обертке от питономодуля), через месяц "движок" выглядит так, что туда смотреть не хочется. Работает и хорошо. А если нет - хрен поймешь, что случилось, так что лучше уже не трогать.
В отличие от движков на Rust. Такие движки почему-то всегда в порядке. Их показывают джунам, как примеры кода. Их элементарно расширять, им не надо тащить говно с npmjs - комьюнити врапперы для говна не принимает.
Так что мой выбор - как бы очевиден.
👍12
Есть такая хорошая книга "Основы маркетинга" от Ф. Котлера. Я не маркетолог, но книгу давно прочитал и всем тоже советую.
Есть там одна фраза, которую я запомнил навсегда "Клиент покупает не ваш товар, ни вы, ни товар ему не нужны. Клиент покупает решение проблемы".
Приведу хрестоматийный пример с веб-серверами. В начале нулевых весь рынок держали IIS и Apache. Про IIS отдельная тема, но у Apache была своя проблема - он тормозил. А интернет требовал скоростей.
Были веб-сервера лучше Apache? Конечно были. Я одно время использовал Zeus - быстрая моща с офигенным, по тем временам просто космическим дашбордом.
Но Zeus стоил космических денег. $1699 по тем временам, примерно как сейчас 5к. Решал Zeus проблему со скоростью? Решал. Но проблема была не настолько серьезной, чтобы покупатель взял и выложил за её решение такие деньги.
Покупателю не нужен был Zeus. И не нужен был его космический дашборд. Поэтому покупатель тюнил Apache, что было намного дешевле, а потом перелез на NGINX, оплатив из кармана разовую переквалификацию персонала.
Zeus сдох.
Есть там одна фраза, которую я запомнил навсегда "Клиент покупает не ваш товар, ни вы, ни товар ему не нужны. Клиент покупает решение проблемы".
Приведу хрестоматийный пример с веб-серверами. В начале нулевых весь рынок держали IIS и Apache. Про IIS отдельная тема, но у Apache была своя проблема - он тормозил. А интернет требовал скоростей.
Были веб-сервера лучше Apache? Конечно были. Я одно время использовал Zeus - быстрая моща с офигенным, по тем временам просто космическим дашбордом.
Но Zeus стоил космических денег. $1699 по тем временам, примерно как сейчас 5к. Решал Zeus проблему со скоростью? Решал. Но проблема была не настолько серьезной, чтобы покупатель взял и выложил за её решение такие деньги.
Покупателю не нужен был Zeus. И не нужен был его космический дашборд. Поэтому покупатель тюнил Apache, что было намного дешевле, а потом перелез на NGINX, оплатив из кармана разовую переквалификацию персонала.
Zeus сдох.
👍21🔥3
Дамы и господа, наконец релизим наш IPC bus, в проде у клиентов уже крутится с июня. ELBUS переименован в BUS/RT, мы зарегистрировали эту торговую марку.
https://crates.io/crates/busrt
В 0.3 нового:
- полная совместимость с Windows
- привели в порядок тех. доки, перетащили в общий infosys (дока по раст-крейту на docs.rs само собой остаётся)
- поубивали немножко ненужных alloc (на скорость не повлияло, но пусть будет без них)
p.s. Торговую марку UK IPO что-то задерживали. При Карле теперь всё подписывают на неделю позже. Надеюсь, это у них временно.
https://crates.io/crates/busrt
В 0.3 нового:
- полная совместимость с Windows
- привели в порядок тех. доки, перетащили в общий infosys (дока по раст-крейту на docs.rs само собой остаётся)
- поубивали немножко ненужных alloc (на скорость не повлияло, но пусть будет без них)
p.s. Торговую марку UK IPO что-то задерживали. При Карле теперь всё подписывают на неделю позже. Надеюсь, это у них временно.
🔥8👍3
Наши будни
- Дашборд подвисает!
- Да нет, всё в порядке...
- Открой вот эту страницу, поставь тут две галочки, теперь открой вот ту страницу в трех табах. Да не в двух, а в трех! Говорю, не в четырех, а в трех! Во! Видел?
- Дашборд подвисает!
- Да нет, всё в порядке...
- Открой вот эту страницу, поставь тут две галочки, теперь открой вот ту страницу в трех табах. Да не в двух, а в трех! Говорю, не в четырех, а в трех! Во! Видел?
😁18💩1