Pull to refresh
8K+
2
Антон Решетников@MachineGate

Разработчик систем ЧПУ

15
Rating
1
Subscribers
Send message

Благодарю вас за фидбэк еще раз, я сделал выводы и учту это при подготовке следующего материала, было интересно обсудить с вами детали 🤝

На самом деле, вы очень сильно недооцениваете сложные программы обработки. Там могут быть миллионы строк и очень плотный поток точек. Так что речь не о километрах, а о вполне реальных объемах.

Произвольные объекты на стеке в C# создать нельзя, это так, но это осознанное ограничение языка. Для поставленной задачи примитивов вроде ref struct, Span<T> и stackalloc более чем достаточно. В C++ доступно больше возможностей при работе со стеком, но это сопряжено с рисками.

Что касается совета "начать разбираться в C++" - я специализируюсь на C#, и статья написана именно про C#, а точнее про то, что на нем можно эффективно решить задачу, которую классически решают на C/C++. Для микроконтроллеров, где я действительно использую C++, нужны совсем другие, более приземленные подходы. Знать концепции C++ полезно, я не спорю, но требовать от автора статьи по C# глубокого понимания C++ не совсем корректно.

Приветствую

Рад что вам моя работа пришлась на злобу дня, для вашего случая скорее нужен патчер G-кода, насколько я понял. Вы можете вывести формулу зависимости Z от XY, выбросить все слои после парсера, кроме постпроцессора (придется немного поменять API слоев, фабрику пайплайна и его конструктор с контекстом) и написать свой постпроцессор, чтобы он пересчитывал Z по вашей формуле, а потом сохранить выхлоп в файл. Если нужна будет помощь - вы можете написать мне по контактам в профиле, постараюсь ответить по возможности.

Приветствую

По факту библиотека и занимается тем же, чем занимается часть на Python в Klipper: она парсит G-код, планирует траекторию, готовит байткод. Я уже писал выше, что упустил важный нюанс в самой статье - не отметил что под RT подразумевается именно Soft RT, то есть от ОС мы все таки зависим и она действительно может переключить контекст потока на антивирус или задержать выполнение, от этого мы не застрахованы, но сам поток данных должен быть предсказуем. Это то, что библиотека обеспечивает.

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

400 000 строк в секунду - это абсолютный оверкилл для станка, вы правы, я упоминал, что слишком увлёкся оптимизациями в целях исследования возможностей платформы, так что это просто пропускная способность библиотеки (она точно не станет бутылочным горлышком). Для реальной задачи с железом идеально подходит алгоритм стримингового конвейера с двойной буферизацией, внедрением которого я сейчас занимаюсь. А вот для CAD/CAM обработка 400 000 строк в секунду как раз полезна, обрабатывать сразу большие объёмы предпочтительнее, чтобы собрать всю диагностику для пользователя одним батчем и показать список ошибок без UI-лага как можно быстрее.

В целом вы правы, детерминизм без алгоритмических гарантий это фикция, но в данном случае масштабируемость от данных близка к линейной (на больших объёмах идёт упор в скорость RAM при копировании данных в слое постпроцессинга), в остальном общий цикл детерминирован и линеен. Для стриминга на МК этого достаточно.

Про кастомные аллокаторы - да, подменить можно, но не везде и не всегда, разные контейнеры могут быть несовместимы с разными аллокаторами. В С# такой возможности и правда нет, но это больше деталь архитектуры, здесь для этого как раз и существуют примитивы низкого уровня типа ArrayPool<T>, Span<T>, stackalloc и т.д. Просто другой подход, легковесные обертки, вместо кастомизации.

Про то что работа со стэком уступает остальным - я бы попросил конкретики, чем именно уступает? В C# есть ref структуры, stackalloc и т.д., которые ещё и жёстко контролируются для безопасности. Если речь о размере стэка или гибкости управления - насколько мне известно, в С++ стэк тоже ограничен и переполнение так же является проблемой.

Я не большой специалист в С++ и конкретно по работе с RAII, но, насколько мне известно, он требует такой же высокой дисциплины в работе как и любой объект с ручной очисткой в .NET, не готов вступать в полемику по этому вопросу, не зная устройства этой системы под капотом. Поправьте меня, если я ошибаюсь.

Стоит оговориться, что при запуске рантайма внутри ОС это априори будет Soft RT, я об этом не упомянул, каюсь. Но то, зачем нужно RT и детерминизм выполнения в самой статье затрагивается - это необходимо, если мы используем библиотеку как часть middleware на ПК, чтобы при обработке буфер траектории/команд на микроконтроллере внезапно не опустошился из-за GC пауз или аллокаций, поток должен быть предсказуемо плотный.

На счёт С и С++ я и правда немного обобщил, современный С++ намного безопаснее С, но проблема string и vector в том, что они алоцируют память в куче, чтобы избежать фрагментации и промахов по кэшу все равно придётся писать кастомные арены, аллокаторы или использовать что-то по типу паттерна Object Pool. Мой посыл был в другом, в .NET компилятор и рантайм сами пресекают большинство потенциально опасных вещей по типу выхода за границы массива, плюс им можно полностью делегировать управление памятью в Cold Path, а в С++ придётся следить за этим самостоятельно на всех уровнях.

Я не спорю, что вызов из другого ЯП остаётся болью, таскать за собой полноценный Core CLR и JIT это даже не стрельба из пушки по воробьям, это уже артобстрел муравейника, можно попытаться использовать NativeAOT и скомпилировать .dll или .so, как я уже говорил выше, посмотреть что он за собой потянет, но главный вопрос в том: а зачем? Основной тейк моей статьи как раз в том, чтобы не мучиться со связыванием модулей на разных языках и писать на .NET в экосистеме .NET. Если остальная экосистема написана на Rust или C/C++ - пишите на них, моя библиотека вам нужна как собаке пятая нога, это будет архитектурным излишеством.

Приветствую

Благодарю за развёрнутый фидбэк по статье, и здоровый скепсис)

Но давайте проясним несколько моментов:

Я не предлагаю писать прошивки для микроконтроллеров на .Net, это очевидно очень сомнительное решение, C/C++ прекрасно работают. Ядро обработки предназначено для работы на машине, которая управляет станком, его задача это только парсинг G-кода и получение байткода для станка, который уже в последствии стримится на микроконтроллер.

Про то что Avalonia и т.д. не предназначены для Embeded - очевидно это так, но .Net не существует в вакууме, вы можете использовать это ядро + Avalonia для построения CAD/CAM, сборку под Web Assembly, для онлайн-визуализатора, продвинутое логирование, ASP.NET для веб-интерфейса управления. Главное преимущество в том, что не придётся связывать несколько модулей на разных ЯП и придумывать им интерфейсы для связи.

Про безопасность и костыли - я явно указываю, что сырые указатели и NativeMemory это осознанный выбор, инкапсулированый внутри библиотеки для достижения максимума предсказуемости поведения и контроля, наружный API безопасен, а в С/С++ весь код потенциально опасен. То есть я предлагаю осознанно инкапсулировать небезопасность внутри библиотеки, сохранив остальной код под защитой рантайма.

Про вызов из другого ЯП - что мешает использовать [UnmanagedCallerOnly]? Если будет стоять задача вызвать библиотеку из другого ЯП её можно спокойно адаптировать и скомпилировать в нативную .dll или .so с экспортом функций по стандарту C ABI.

Приветствую

Раньше действительно нужно было использовать Marshal.SizeOf<T>, так как его можно было вызвать в safe контексте, а sizeof нет, сейчас можно использовать sizeof. Ещё зависит от задачи: sizeof возвращает размер в оперативной памяти с выравнивание, Marshal.SizeOf<T> возвращает размер после маршалинга, как она будет передаваться в P/Invoke, то есть для внешнего кода и учитывает атрибуты маршалинга.

По поводу таблицы символов - да, вы правы, либо new { ... } и ручками забивать страдая, либо попробовать SourceGenerators, но слабо представляю как это тут применить.

Information

Rating
591-st
Location
Челябинск, Челябинская обл., Россия
Date of birth
Registered
Activity

Specialization

Инженер встраиваемых систем, Системный инженер
C#
C++
ООП
Git
CI/CD
Английский язык