Комментарии 88
Микросервисы на яве едят под 1-1.5гб рам (спринг бут, mvc, все дела). Есть ли смысл (в плане уменьшения потребления рам) смотреть в сторону переписывания нескольких таких микросервисов на раст?

Ну если у вас крутится под сотенку контейнеров для обработки медиа, то разница между 200 метрами и 1,5 гигами будет заметной.

Есть смысл для начала выкинуть этот самый бут/mvc и переписать на той же яве.

Java в работе с памятью не так плоха, есть GraalVm и те же микрофреймворки типа quarkus и иже с ними
Потребление памяти в них приятно удивляет

Есть. Если есть интерес к Rust и хочется его опробовать — то так и нужно сделать. В противном случае имейте ввиду, что придется потратить время на освоение программирования на Rust.

НЛО прилетело и опубликовало эту надпись здесь

Кажется, единственное (кроме borrow checker’а, конечно), что rust предлагает принципиально нового в сравнении с другими компилируемыми языками — это first class citizen AST.


Вот именно про AST было бы весьма интересно, потому что тогда можно было бы говорить о действительно интересной парадигме, позволяющей вывести интероперабельность на новый уровень — а не очередном невнятном синтаксисе и «avoid success at any cost».

Справедливости ради стоит отметить, что в LISP-подобных это есть уже точно не 1-е и не 2-е десятилетие.

Если TH — это Type Hints, то я не понял вопрос. «Чем ананас более фрукт, чем яблоко?» — да ничем, просто TH как бы не являются meta-language facility, а AST является.


Вот я беру AST эликсира в узких местах — и почти диффеоморфно конвертирую его в Julia’s AST. И арифметика, написанная на эликсире, внезапно работает быстро. Или я могу нашему RnD реализовать алгоритм, не засоряя голову синтаксисом Julia. Как тут помогут TH?

В данном случае имелся в виду Template Haskell. Могли бы и сами догадаться зная написавшего…

Во-первых, я не настолько тупорылый дегенерат, чтобы принимать во внимание личность человека в дискуссии в интернете. Во-вторых, я написавшего впервые вижу. И, наконец, я написавшего немного уважаю, поэтому вариант Template Haskell отмел в контексте вопроса сразу, как GHC extension к Haskell 98. Я не думал, признаться, что у кого-то достанет смелости назвать это «first class citizen» в языке.

Я не думал, признаться, что у кого-то достанет смелости назвать это «first class citizen» в языке.

Мы же это уже обсуждали — надо прекратить пинать дохлую лошадь и признать, что попытки иметь какой-то стандарт хаскеля после Haskell Report 2010 провалились (ибо никому оказались не нужны), а затем принять, что хаскель — это вот ровно то, что реализовано в ghc.

GHC extension к Haskell 98

Ключевое слово 98, даже не extension. Это костыль, вкряченный сбоку. Я же не говорю, что оно не работает. Как-то работает, наверное. Даже в руби спустя лет двадцать добавили какое-то подобие AST, это всегда возможно, просто в силу структуры языков программирования.


Тут же, насколько могу судить, люди об этом думали с первого дня. Правильная реализация компилятора должна проходить через AST и позволять писать код прямо на нем. Лиспы так изначально проектировались, например.

Ну «ДедушкаФуд», главный хаскелист всея Хабра. И знаток прочих мозголомных языков, как нистранно использующихся на практике. У меня мозг взрывается, когда смотрю на его APL-подобные листинги. ;-)

Призывы в конце статьи как-то очень сильно напоминают «первая доза rust бесплатно» :-)
Если вы действительно хорошо разбираетесь в системном программирвоании, и можете писать на С++ с закрытыми глазами, то вам стоит писать WEB на rust. Иначе, вы будете часами сидеть перед функцией, которая принимает параметры возвращаемые из формы, и горько плакать, потому что перед вами будет стоять непосильная задача распарсить эти параметры в JSON.

Да нет же, есть куча удобного в C++ для этого, тот же nlohmann/json к примеру.
От чего такие обвинения? От незнания?

А можете показать пример, как это всё выглядит? А то на Rust я могу сделать вот так:


use serde::Deserialize;

#[derive(Deserialize)] // <-- единственное, что нужно добавить к определению
struct User {
    name: String,
    age: u16,
    attributes: Vec<String>
}

fn main() {
    let input = r#"{
        "name": "John Doe",
        "age": 32,
        "attributes": ["smoker", "programmer"]
    }"#;
    let user: User = serde_json::from_str(input).expect("parse error");
    assert_eq!(user.name, "John Doe");
    assert_eq!(user.age, 32);
    assert_eq!(user.attributes, ["smoker", "programmer"]);
}

И всё прекрасно работает

Там есть нечто вроде этого — макросы NLOHMANN_DEFINE_TYPE_XXX. А вот что касается возможности парсить json, так сказать, «js-style» (в динамические структуры) — в serde я этого не увидел, по крайней мере, сходу беглым взглядом.

Все эти макросы плохи тем, что если у вас одна библиотека предлагает NLOHMANN_DEFINE_TYPE_XXX для поддержки жсона, другая — BOHMANN_DEFINE_TYPE_YYY для поддержки бсона, а третья — BERMANN_DEFINE_TYPE_ZZZ для поддержки BER, то совершенно непонятно, как их совмещать.

Там есть нечто вроде этого — макросы NLOHMANN_DEFINE_TYPE_XXX

Благодарю. А теперь покажите, пожалуйста, аналоги rename, default и flatten, а что-то руками писать свой десериализатор страшно не хочется.

Через предлагаемые макросы это, наверное, не сделать. Возможно, это можно как-то автоматизировать путем добавления своих ad hoc макросов, это нужно разбираться. В любом случае, говорить, что на C++ при необходимости распарсить json ты прямо будешь плакать и не знать, как решить сию "непосильную задачу", может либо пропагандист (в плохом смысле), либо просто человек, не имеющий представления, о чем он говорит.

Не совсем аналогичное, но в том же ключе: Cereal
Вместо макросов — пишем метод или функцию serialize или пару других вариантов. Из минусов — активно использует шаблоны для выбора требуемых перегрузок.

А можно на Расте писать GUI-шные программы? Есть ли какая-то IDE и Form Designer? Чтобы по степени удобства было сравнимо например с Lazarus?

Можно, но все еще в довольно зачаточном состоянии. Есть несколько врапперов, над Qt, GTK итп. Есть несколько сырых rust-centric фреймворков. Пока самый "взрослый" способ делать GUI, из тех, что я нашел — это веб, как раз yew.


https://www.areweguiyet.com/

Часть про Web освещена как то слабо, ждешь чего-то большего личного опыта, кейсов
В каких случаях и по каким показателям, кроме performance, дает ощутимый прирост в разработке, стоимость поддержки и т.д.

До главки "Javascript" было хорошо. А дальше, как говорится, панеслася…
1) JS в 2021 году на 99.9% (0.01% приходится на исполнение JS в странных браузерах без JIT-компиляции) всё так же проходит JIT-компиляцию. Никто вам его не "просто берет и начинает выполнять".
2) Критиковать размер зависимостей в JS рядом с разговорами o wasm — очень смешно. Потому что если в ноде у вас ситуация "очень большой объем зависимостей на JS и немного меньше, если нативно" — более-менее распространена, то вот на фронте гораздо более распространена обратная ситуация — попытки сделать фронт на wasm ведут к тому, что итоговый размер пакета куда больше объема JS (потому что в пакет wasm вы вынуждены складывать то, что уже бесплатно есть в браузере для JS).

JIT — не панацея. Есть исследования, к сожалению, ссылки не сохранял, что JIT не может работать настолько же эффективно, как нативный код в принципе.


Сборка мусора — тоже добавляет сложностей и неэффективностей, которые никак не обойти.

Да ну конечно не может. С этим никто и не спорит.
Но дело в том, что "работать максимально эффективно" нужно далеко не везде.

в пакет wasm вы вынуждены складывать то, что уже бесплатно есть в браузере для JS

В каком смысле? wasm (как и сам JS) имеет доступ ко всему что в браузере есть для JS — туда не нужно что-то дополнительно складывать, разве что очень короткий прокси сделать. Если кто-то это делает — то это от незнания, а не по необходимости.

В прямом. Если вы из wasm будете ходить в браузерный мир, то от единственного преимущества wasm (быстродействия) не останется совсем ничего. Всё будет работать со скоростью того самого JS, который вы будете постоянно дергать.

Преимущество wasm проявляет себя исключительно в вычислительно-интенсивных операциях, а всё что касается UI, рендеринга и прочего — это всё равно делается через песочницу браузера, а она абсолютно идентична что для wasm что для JS, ускорить это невозможно в принципе, разве что реализовать свой специализированный браузер на WebGL.


То есть чтобы вы не "складывали" в wasm — если это касается DOM, картинок, стилей etc — это будет ровно так же быстро как и в JS, но никак не быстрее.

Преимущество wasm проявляет себя исключительно в вычислительно-интенсивных операциях

… и вот поэтому если вам для "вычислительно-интенсивных операций" понадобится ГСЧ, вы как миленький положите код этого ГСЧ в пакет, потому что обращения к браузерному Math.random() все ваши преимущества размажут.
И ГСЧ — это, безусловно, мелочь. Но обработка строк — уже не такая мелочь. Сложные структуры данных — аналогично. И так далее и так далее.

Все современные популярные браузеры содержат высокэффективные реализации примитивов и криптографии, в т.ч. штук типа Math.random() и обработки строк (примерно также это сделано в NodeJS) — таким образом нивелируя различия по скорости для wasm и JS.


С учётом этого, тащить в wasm имеет смысл только то к чему нельзя обратится из JS — всё остальное с вероятностью 99% уже и так максимально эффективно, а сами браузеры, насколько мне известно, не содержат в себе библиотечного кода на JS.

Извините, но вы уже начали спорить со своими собственными сообщениями. Попробуйте привести свои мысли в порядок.


Либо вы кладете в пакет wasm весь нужный вам "для вычислительно-интенсивных операций" код, либо вы обращаетесь к браузерной реализации по маршруту wasm -> обертка js -> экосистема браузера -> обертка js -> wasm. И тогда это всё работает со скоростью js.

Либо вы кладете в пакет wasm весь нужный вам "для вычислительно-интенсивных операций" код

Если он специфичный для моего приложения — то в браузере его не будет "бесплатно" и для JS тоже.


Выше вы написали:


в пакет wasm вы вынуждены складывать то, что уже бесплатно есть в браузере для JS

Повторю — если это уже есть и бесплатно для JS (т.е. без подкачки откуда-то извне) — значит оно бесплатно для wasm тоже, ибо последний имеет прямой доступ к JS API браузера, оба (wasm и JS) выполняются в одной и той же VM.


Т.е. грубо говоря вызов Math.random() из JS и wasm занимает ровно одно и то же время (в случае wasm таки может быть даже быстрее потому что нет оверхеда движка JS), а ваша собственная реализация такого же random() на wasm никогда не будет быстрее браузерной по определению (разве что браузерные девелоперы совсем уж накосячили) — по той простой причине что браузерная почти наверняка написана на C/C++ и хорошо оптимизирована, а wasm (будучи банальным байткодом, похожим по сути на JVM) просто проходит через JIT и не достигнет такой же производительности.


Если у вас есть сомнения — можете сделать бенчмарк, результаты вас удивят, а ещё я бы очень хотел посмотреть на пример того что бесплатно для JS но дорого для wasm (в пределах одного браузера).

Либо вы кладете в пакет wasm весь нужный вам «для вычислительно-интенсивных операций» код, либо вы обращаетесь к браузерной реализации по маршруту wasm -> обертка js -> экосистема браузера -> обертка js -> wasm. И тогда это всё работает со скоростью js.
И даже медленней. В отличии от «js only», у вас появятся еще накладные расходы от взаимодействия «wasm <--> js».

Что-то про fork и потоки намешано не то. fork() — это про процессы, а не потоки. Inter-processing communications всё же слегка сложнее коммуникации между потоками.


Пример с zero cost стоило сделать с другой конструкцией всё же.

Я вообще не понял про zero cost. Я всегда думал, что это про то, что если в языке есть какая то фича, но ты ей НЕ пользуешься, то наличие этой фичи — никак не влияет на твою программу.
Ну например в C++ виртуальные методы — zero cost, не используешь их, не платишь за косвенность вызова. А исключения — не zero. Компилятор должен сильно поприседать, чтоб понять, что тут исключений нет и try finally делать ненужно


А тут явно вызвали функцию fork(), понятно, что это уже не zero cost и пофиг что она конкретно делает.

Исключения давно zero-cost для случая невыкидывания экзепшона.


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

Под x86 zero cost?


тогда вы должны будете признать, что даже ссылки и указатели в C++ не являются zero-cost.
Хм, а как ссылки и указатели мешают оптимизации если я их не использую?

Фиг знает, под x86 (не _64) я очень давно код не собирал. И не знаю никого, кто собирал бы под x86 требовательный к производительности код.


Хм, а как ссылки и указатели мешают оптимизации если я их не использую?

Компилятор далеко не всегда может доказать, что вот эти два указателя не алиасятся (даже если вы их не алиасите сами), или что вот эта переменная не изменится при записи по вот тому указателю.

Спасибо. Как беглый исторический экскурс прочитал с большим удовольствием.
Классные статьи про классный язык, начал читать книгу по вашему пути… Но найдите таки правильный синий экран. Который про ошибку обращения к памяти, а не про обращение к выгружаемой памяти в драйвере не с того уровня ;)
я считаю подход начинать с идеи того, что хотим сделать, мотивирует больше, чем детали работы железа. процессор, память и т.д.
Оффтоп: У Буратино было пять яблок. Он съел два. Сколько яблок осталось у Буратино? Думаете три? Фиг вам. 32764! Память кто будет инициализировать при работе с переменными?

«У Буратино было пять яблок» это и есть инициализация. Чтобы создать правильную ошибку не инициализированный переменной нужно например «Буратино дали пять яблок...»

Таки не факт, что полученная от ОС неинициализированная память была забита 0xFF, может там были DE AD и тогда яблок осталось 57003, в случае беззнакового :-)

Ой и правда. В оригинале было так: Буратино дали пять яблок. Он съел 2. Сколько яблок у Буратино?

Почему я использую Rust в вебе — и в рабочих, и в личных проектах:


  1. Хорошая производительность "из коробки" и хороший потенциал для тюнинга оной в дальнейшем.
  2. Универсальность языка и хорошая поддержка модульности — можно активно переиспользовать код в широком спектре разных проектов.
  3. Поддержка WebAssembly, возможность писать клиент и сервер на одном языке с использованием общего кода.
  4. Развитая система типов упрощает доработку и поддержку.
  5. Относительно просто писать многопоточный и асинхронный код.
  6. Удобное управление ресурсами (встроенное RAII как для памяти, так и для чего угодно еще).
  7. Легковесность, отличный тулинг.

Но я бы не советовал его брать тем, кто:


  • Не готов осваивать новую концепцию программирования (владение и заимствование).
  • Не готов терпеть сыроватую экосистему, в которую время от времени нужно котрибьютить.
  • Не собирается развивать свой проект, а хочет быстро написать прототип и выбросить.
  • Предпочитает программирование в стиле REPL.

Плюс к тулингу. В своё время подсел на раст именно за элементарную сборку под все нужные платформы — надо было иметь возможность получить из одного кода и бинарник для запуска на линуксовом серваке, и бинарник для встраивания на слабую (точнее, занятую более важными процессами) железяку на винде в случае отсутствия доступа к сети.

Почему я использую Rust в вебе — и в рабочих, и в личных проектах:


Можно чуть больше инфы что за проекты? Без закрытой бизнес инфы, само собой. Хотя бы примерную референс архитектуру (риалтайм аналитика, iot etc), сколько отдельных сервисов в системе и где там используется Rust.

Один проект — это торговая площадка, криптовалютная биржа. Ее ядро написано на Rust (actix, gRPC, RocksDB) + некоторые дополнительные сервисы и инструменты.


Другой проект — платформа для запуска децентрализованных приложений в изолированном окружении. Клиент, сервер и сами приложения пишу на Rust (actix_web, yew, wasmer, libp2p).

Замечательно! Не хотите написать статью? А то народ требует хлеба и зрелищ а я по колено в коде компилятора, пишу следующую статью. И до этого вэба не доберусь. А как видно из опросов, веб на втором месте.

А изолированное окружение на основе чего сделано? cgroups+namespaces, systemd-nspawn или что-то ещё?

Спасибо, хорошее описание… Вебку на Rust — это жуть, лучше другие вещи. Вот например блокчейн, код одного из которых видел однажды видел на Rust-е, и это было единственное, что вообще видел на нем…

Почему жуть? Вот перелопатить половину JavaScript-приложения только для того, чтобы понять все возможные значения, которые могут посылаться в данную функцию — вот это жуть. Rust от такого спасает.

Не знаю что я делаю не так, но, я сравнил 2 примерно одинаковые утилиты на golang и rust, которые разбирают большой xml файл (размером более 22 гигабайт), — просто вытаскивают из него нужные элементы, используя SAX парсинг (такой DOM не влезет в память). Так вот утилита на golang, которая делает сильно больше (разбор + создание неких объектов + вставка этих объектов в mongodb), работает в 2 РАЗА БЫСТРЕЕ (6 минут против 14), при этом код на rust просто считает количество открытых и закрытых тегов, ничего не вставляет в базу и не создает.

В качестве SAX парсера на rust я использовал xml-rs = «0.8» (https://docs.rs/crate/xml-rs/0.8.3)

Хотелось бы посмотреть на код в обеих утилитах, а заодно узнать, насколько быстрее будет с quick-xml

Присоединяюсь. Кажется, это повод устроить бессмысленные бенчмарки.

c quick-xml все сильно быстрее.

В общем вывод — все зависит от используемого crait
Замена xml-rs на quick-xml уменьшила время разбора с 880 секунд до 25 т.е. в 35 раз!

что-то явно не так с xml-rs

При работе с xml-rs у меня io приложения порядка 30 мб/сек, с quick-xml доходит до 1 гб/сек
полезная инфа, спасибо. Надо держать ухо востро с крэйтами. Знать бы теперь как их навскидку оценивать
Навскидку — по количеству загрузок, но нельзя забывать, что это могут быть «миллионы мух».
Если чуть детальнее — смотреть список зависимых крейтов, если там есть другие относительно популярные — тогда чуть понадёжнее.
При поиске на очень конкретную тему рекомендую в первую очередь смотреть на keyword:
crates.io/keywords/xml
Тогда у вас
quick-xml v0.20.0
High performance xml reader and writer
был бы сразу вторым.

Но соглашусь, к сожалению самое популярное не всегда самое подходящее.
на самом деле 25 секунд оказалось только в первый раз — все остальные за 15 секунд проходят :) так, как кэширование OS начинает работать, и скорость IO возрастает до 1.5 Гб/сек, разумеется такие цифры на NVMe SSD получаются
Tokio — это «всего лишь» асинхронная база для любого проекта, не обязательно веб.
Проблема с компилируемыми языками на сервере называется «а как это собирать?». Linux — это ж не благословенная винда, где вы можете собрать всё на вашей рабочей машине, потом просто скопировать готовый exe'шник на сервер и всё будет работать. Тут так нельзя. И что делать? Тянуть на сервер компилятор и весь набор инструментов/библиотек, а потом прямо на сервере вести сборку? Как-то оно не очень выглядит.
Для этого придумали RPM/DEB пакеты, или даже Docker — упаковал на своей машине разработчика, перенёс любым способом и развернул одной командой.

Пакеты с бинарниками обычно прибиты гвоздями к конкретной (мажорной) версии системы где собирались, а докер точно такая же зависимость как компилятор с библиотеками — он не стоит по умолчанию на всех без исключения системах, не везде может быть установлен (по административным или техническим причинам) и (в зависимости от приложения) может оказаться не бесплатен в плане производительности (все эти слои поверх fs/net чего-то стоят) или удобства конфигурации (ему нужны свои очень специальные правила для файрволла), да и вообще докер часто это просто способ масштабирования "кое-как удалось собрать" и "у меня всё работает" на массы чайников которым не удалось собрать или у кого не получается заставить работать.


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

Хорошо, а что вам мешает завести билд-машину с той же версией ОС, что и на целевой(-ых) машинах и опять-таки собирать в пакеты?

Не у всех есть ресурсы или бюджет для сборки на всех возможных вариациях для всех (даже только популярных или актуальных) систем, особенно если это open source который пишется парой студентов из небольшой деревни в Индии.


К сожалению, порог входа для дистрибуции бинарников очень высок в случае Линукса, а само пространство очень фрагментировано, как по софту так и по политикам.

А причём тут опенсорс и всевозможные вариации, когда обсуждалась проблема применимости компилируемых языков на сервере? Уж для своих-то серверов собрать правильную билд-машину вполне возможно.

ну сейчас руками не принято собирать, для этого используют CI/CD и по возможности докер (который содержит всё необходимое)

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.