Оптимизация Rust

Rust для веб-разработчика — быстрый старт и стремительный полет

Всем привет! Сегодня хочу поделиться опытом изучения языка и быстрой реализации высоконагруженного сетевого проекта, использующего так популярные и востребованные сейчас неблокирующие асинхронные сетевые соединения, на новом, красивом, элегантном и очень эффективном языке Rust.
Особый упор в посте сделаю на быстрое и ясное объяснение возможностей языка и платформы специалистам, имеющим большой опыт в веб-разработке, ибо сам таким и являюсь. Существует заблуждение, что кривая вхождения в Rust — очень-очень крутая. Но я покажу, что это далеко не так. Наливаем кофе и погнали!

Чтобы материал хорошо залег в голову и сердце, неплохо кратко вспомнить, что люди хотели сделать в программировании за последние 50 лет и что в итоге у них получилось. Без обид, только личное субъективное мнение и холивар, подкрепленный 20-летним опытом разработки.

Низкоуровневые языки: C, C++

Понятно, что можно писать программу сразу в виде цифр на машинных кодах и многие этим занимались на ZX Spectrum, БК0010-01 и на PC — код получается очень быстрым 🙂 Но мы люди, в голову много информации не помещается, мы отвлекаемся и поэтому даже изобретение ассемблера не особо помогло — код на таком низком уровне пишется очень редко и очень метко и, скорее всего, если вы не занимаетесь разработкой драйверов, микроконтроллеров или хитрых встраиваемых систем, это в жизни не пригодится.

В начале 70-х в Bell Labs придумали язык C, который прижился благодаря лаконичному синтаксису и очень «дешевым» абстракциям, практически став «переносимым ассемблером». Понятно, что если принять постриг, 10 лет писать на C ночами, не есть мясо, молиться и не отвлекаться на соцсети и формы прекрасного пола, то можно писать очень даже полезные и быстрые программы, о чем красноречиво свидетельствуют GNU, прекрасные производительные игры, не всеми любимая, но безальтернативная по качеству Windows и еще можно привести много примеров.
Но обратная сторона медали постоянно дает о себе знать — регулярно открываемые дырки в безопасности (создана целая индустрия по «дыркам в софте»), обусловленные дырками в концепции самого языка С — компилятор подобен безответственному быку, с неимоверной мощью, интенсивным оргазмом и короткой памятью. Любая неосторожность — и можно не просто уронить программу (разыменование нулевого указателя, двойное освобождение указателя, выход за пределы массива), а безвозвратно испортить данные и долго этого не замечать, пока не начнут звонить клиенты и когда уже поздно («неопределенное поведение», отличающееся от компилятора к компилятору).

  • опытная, от слова «очень», команда (годы практики, «монахи» программирования)
  • хороший статический анализатор кода
  • департамент тестирования (в коде могут быть дырки, оставленные безответственным компилятором, которые долго могут давать о себе знать)
  • согласованные всеми членами команды требования, которые тщательно контролируются (не используются «сырые» указатели, строгая инкапсуляция, жесточайшая дисциплина именования переменных, инициализация объектов и т.п.)

Понятно, что соблюдение указанных требований, особенно в контексте возрастающей потребности бизнеса на «работающий без внезапных сюрпризов код», очень дорого. Код в подобных проектах пишется долго, тестировать его нужно продолжительное время и тщательно, но, иногда, без C/C++, до изобретения Rust, действительно сложно БЫЛО обойтись.

Еще раз резюме по С/C++ — мы имеем мощный, но «безответственный» компилятор с «текущими абстракциями», очень мало помогающий разработчику. В результате все проблемы перекладываются на плечи программиста. Если хоть один программист в команде не опытный, не очень осторожный и не знает всех тонкостей работы компилятора (на самом деле никто не знает всех тонкостей и их находят пользователи потом) — жди беды. Но зато программа работает быстро и, вероятно, правильно 🙂 Это, разумеется, породило целый рынок «костылей» — статических анализаторов, платить за которые должен, как оказалось, Заказчик. Возникает вопрос — а разве нельзя было что ли написать более строгий и безопасный компилятор, помогающий разработчику и рождающий программы без сюрпризов и низкоуровневых дырок в безопасности?

Java, C#, Kotlin

  • код пишется один раз под виртуальную машину, которая работает на любых архитектурах (windows, linux, mac)
  • разработчик больше не управляет памятью напрямую, как в C/C++ — это перекладывается на плечи «сборщика мусора»; так снимается риск неопределенного поведения, незаметной порчи данных и потенциальных низкоуровневых дырок в безопасности
  • код компилируется «на лету», во время работы программы (Just_In_Time-компиляция), т.к. известно, что в программе активно и часто выполняется только малая часть, поэтому все компилировать смысла нет
  • проще стало писать эффективный многопоточный код, т.к. была строго специфицирована модель памяти (гораздо раньше, чем в C++), но, о чем далее, не все проблемы с «логической надежностью работы нескольких потоков» были решены (остались возможны deadlocks, например или data-races)

Разумеется, появление такой дружелюбной платформы позволило писать много полезных и бесполезных программ, чем сразу воспользовался бизнес. А поддержка обратной совместимости в Java в 15 и более лет обусловила такую популярность технологии в мире энтерпрайза.

Да, у меня тоже возникают аналогии с безалкогольным пивом и резиновыми женщинами.

  • из-за логической «дырки» в системе типизации, которая перешла по наследству из C/C++, в Java попал тип «Null», который и по сей день порождает много проблем и постоянно приводит к падению программ «не очень опытных» программистов, которые не знают про тип Optional и не интересуются монадами из функционального программирования
  • проекты на Java, работая иногда незначительно медленнее, требуют на порядки больше оперативной памяти, чем на C/C++, нужной сборщику мусора (у нас несколько проектов «кушают» десятки-сотни гигабайт ОЗУ); это часто не является прямо проблемой, т.к. цены на оперативную память снижаются, но «осадочек остался»
  • несмотря на jit-компиляцию и большие инвестиции в ускорение сборщика мусора (которых много и новые появляются регулярно и постоянно говорят: «попробуйте новый GC, он значительно лучше»), уже 20 лет некоторые высоконагруженные проекты на Java работают с регулярными паузами по несколько секунд, которые нельзя убрать никак (происходит вынужденная сборка мусора и как винтики в GC не крути, сборщик мусора просто не успевает все убирать, даже работая параллельно и даже пожирая больше ресурсов, чем сама программа)
  • известно, что GUI-приложения на Java иногда зависают и тормозят, вызывая гнев пользователей, из-за той же сборки мусора и надежды нет и не предвидится
  • синтаксис языка очень многословен и избыточен (нужно писать и затем читать слова «public static functon» вместо, скажем, «pub fn» или «def»), вынуждая иногда разбивать пальцы об ногти и вызывает объективную резь и кровотечение из глаз
  • резкое снижение требований к уровню квалификации разработчиков и достаточная низкая кривая вхождения породило много кода «странной степени свежести», постоянно дающего о себе знать на всю жизнь запоминающимся зловонием

После прочитанного должно быть понятно, что все на Java писать нельзя, это будет писаться довольно медленно, потом будет под нагрузкой регулярно тормозить и зависать на секунды, «жрать» иногда много оперативной памяти (обычно съедается как минимум половина ОЗУ на сервере), производительные игры тоже не попишешь, но какие-то куски бизнес-логики, не особо требовательные к производительности и ОЗУ, особенно многопоточные — вполне можно, полезно и поэтому мы видим такую популярность технологии в мире энтерпрайза. И мы сами регулярно и активно используем Java для сервисов компании.

C#, Scala, Kotlin

«А когда же будет про Rust?» — погодите, нужно еще чуть-чуть подготовиться скушать эту сладкую хурму. Если не рассказать об особенностях других технологий, вы не поймете, почему появился Rust и почему от такой популярный и востребованный.

Итак, пытаясь сделать Java лучше и прогрессивнее, Microsoft, в лице автора TurboPascal/Delphi, в начале нулевых придумал C# и концепцию .NET. Объективно, по мнению многих авторитетных экспертов, да и в курилках разработчиков, «C#» сексуальнее Java, хотя, конечно, пока еще, несмотря на Mono, сильно привязан к Microsoft со всеми втекающими и вытекающими 🙂

Scala, несомненно, большой шаг вперед, т.к. язык, конечно, получился научно-заумный и навороченный, взявший немало полезных и бесполезных вещей из мира функционального программирования. Но вот с популярностью что-то как-то не очень понятно. Однако Apache Spark действительно хорош и популярен, нечего сказать.

Kotlin же популярен, т.к. делает Java более эффективной и простой для начинающих разработчиков, особенно на мобильных платформах, у которых нет времени серьезно изучать программирование 🙂

Но основная проблема и в C# (на платформе .NET), а также в Scala, Kotlin и в других JVM-языках — осталась. Сборщик мусора, Карл, создающий заметную нагрузку на сервер и остановки выполнения кода на секунды при нагрузках и прожорливые требования к оперативной памяти! И сколько еще языков со сборщиком мусора и jit-компиляцией не придумают, указанные проблемы останутся и надежды пока нет, даже в теории.

Скриптинг

«А как же PHP?». Да, сейчас поговорим про скриптинг. Казалось бы, зачем он? Примерно в конце 80-х стало очевидно, что, если нужно быстро решить задачу с помощью кода, не обязательно супербыстрого, причем безопасно, без неопределенного поведения и низкоуровневых дырок, можно написать скрипт. Скрипты писали и раньше, на bash, perl, awk, но, оказалось, что на python можно писать большие-пребольшие скрипты, особенно научные, причем годами!

Lua нашел свою нишу в геймдеве и машинном обучении (Torch), JavaScript — в веб-разработке как на стороне браузера, так и на стороне сервера (все же знают, что «npm» в Node.js написан на «rust»?). Python — в машинном обучении и анализе данных, а также в системном скриптинге. А PHP — прекрасно справляется с серверными задачами по веб-разработке.

  • Безопасный, эффективный код без неопределенного поведения и низкоуровневых дырок в безопасности, использующий популярные алгоритмы и структуры данных (списки, словари, очереди), создается буквально за минуты
  • Очень быстрый старт и пологая кривая вхождения. Достаточно нескольких дней, чтобы разобраться и написать полезный скрипт на python, поменять логику работы nginx через скриптинг на Lua или сделать интеграцию интернет-магазина на PHP
  • Если писать скрипты дисциплинированно, соблюдая CodeStyle и максимально строго, то можно очень быстро решать сложные задачи и создавать большие программные продукты: родилось огромное количество научных библиотек на python, системы управления бизнесом и сайтами на PHP, нейросетевая платформа Torch на LuaJit, игровой скриптинг в очень известных и популярных играх и т.п.
  • Некоторые виды многопоточного программирования, где узким местом является ввод-вывод, довольно эффективно решаются на python. А используя последние возможности python с futures типа «async/await» можно еще проще решать задачи обработки большого числа сетевых сокетов
  • Очень элегантно задача асинхронной обработки большого числа сокетов даже без многопоточности решена в Node.js из коробки
  • Создавать веб-страницы, использовать многочисленные unix-библиотеки, ходить в базу данных по-прежнему легко и удобно с помощью PHP и продуктов на его основе
  • На python, PHP, JavaScript очень удобно проверять гипотезы и делать прототипы за часы, а не месяцы
  • Для аналитики и обработки данных традиционно очень удобно использовать python/R в соединении с большим количеством качественных библиотек (pandas, scikit-learn, seaborn, matplotlib . )
  • Низкий уровень вхождения и очень быстрая скорость написания скриптов иногда, при отсутствии должного контроля над разработчиками, рождает тонны неэффективного и трудно-поддерживаемого кода на любой платформе
  • Отсутствие компилятора, системы типов и статической типизации требует динамической проверки передаваемых в функции и методы параметров на типы и качественного покрытия кода автотестами. Иначе любое изменение в коде может сломать программу и об этом первым узнает клиент, а не разработчик (да, я знаю про TypeScript, но это же костыли и мертвому припарки)
  • Объективно и очевидно, что в языках без статической типизации и компиляции, где многие вещи происходят в runtime, нельзя использовать многочисленные оптимизации и поэтому в ряде задач скрипты работают на порядки медленнее и потребляют в разы больше ресурсов. Несмотря на попытки внедрить jit-компиляцию в python (pypy), PHP (hhvm), JavaScript (трансляция в машинный код, вау, Node.js v8), LuaJIT — давайте не будем себя обманывать: все это выглядит как слабо эффективные костыли. Причина в том, и это нужно понять один раз и навсегда, что из-за сознательной слабой типизации языков, для скриптов вряд ли когда-либо получится написать эффективный runtime, приближающийся по скорости к гораздо более строго-типизированным Java/C#
  • А в python, похоже, никогда не будет эффективной многопоточности, как в Java/C#, из-за GIL

Однако, т.к. в большинстве бизнес-приложений, в т.ч. системах управления сайтами, CRM и т.п. большая часть времени выполнения кода тратится на запросы в базу данных, то преимущество jit Java/C# глубоко нивелируется скоростью написания решений на PHP/python/JavaScript и лично я, для создания веб-приложений, выберу 10-20 строк на PHP, чем 10 000 строк и кучу потрохов на Java/Spring. А PHP7 как-то разогнали так, что он работает быстрее python3 😉

  • очень высокие сетевые нагрузки и «экстремальная» многопоточность, тысячи — десятки тысяч сетевых сокетов и т.п.
  • ограничение на использование оперативной памяти и «железа»
  • интенсивная обработка данных и вычисления, матрицы с миллионами сущностей, GPU (хотя тут может помочь python/numpy/pandas)
  • быстро делаем решение на PHP/python/JavaScript/Node.js, запускаем в бой и начинаем решать задачи клиентов
  • обкатываем фичи, возможности, улучшаем сервисы
  • в редких случаях, по опыту, обычно не ранее, чем через несколько лет, часть таких, уже стабильных по функционалу, сервисов, переписывается на C/C++/Java/Golang/Rust

Функциональное программирование, Lisp, Haskell, F#

Многие, за целую карьеру разработчика, так и не приходят сюда, а вот зря. Крайне полезно понять, почему появилось ФП (функциональное программирование) и почему в некоторых областях оно так популярно.

  • мутабельные переменные
  • циклы с условиями
  • функции, создающие побочные эффекты
  • алгебраических типов данных и pattern-matching по ним
  • отсутствия циклов (только через рекурсию) и мутабельных переменных в пределах доступности вытянутой руки (костыли как это обойти, конечно, можно найти)
  • очень строгой статической типизации и, одновременно, очень удобного автовывода типов Хиндли-Милнера
  • очень мощных функций, с разделением на «чистые» и «с побочными эффектами», с возможностью частичного применения
  • поддержки безопасного параллельного программирования
  • поддержки комбинаторов через монады на все случаи жизни (подробнее дальше, в разделе про Rust)

Haskell откровенно не взлетел по причине агрессивных «понтов» — чтобы хорошо понять его терминологию, нужно быть, как минимум, кандидатом наук со специализацией в области одной из лидирующих теорий в современной математике: теории категорий. А еще в Haskell явно намудрили с «ленивостью», то ли граф выполнения память переполнил, то ли выполнение началось, и память кончилась потом, что нередко больно бьет по его боевому применению. Именно поэтому солдаты в бою на территории противника бросают Haskell и берут автомат Калашникова.

И, конечно, совсем забыли про сборщик мусора — в Haskell он, к сожалению, тоже есть, что ставит его по эффективности и производительности на одну ступень с конкурентами типа Java/C#.

Но это не означает, что язык не нужно учить. Haskell развивает программисту, в первую очередь, мозги, так нужные для написания ясных, эффективных и легко поддерживаемых годами программ. Известно ведь, что кроме скриптинга крайне полезно знать хоть один из «настоящих» языков программирования — и Haskell тут очень достойный кандидат.

Новые «C/C++» — Golang, D

Системное программирование, еще в начале нулевых, реализовывало себя в основном через C/C++ (возможно, нельзя не упомянуть в этом контексте и знаменитый Forth). А мнение Линуса Торвальдса про C++ как тогда, так и сейчас не утратило своей актуальности, несмотря на попытки великого и ужасного Андрея Александреску изменить ситуацию в D (со сборщиком мусора — ну как же так, опять наступили на эти грабли).

  • встроенные в язык «green threads» (аля корутины), но они есть уже даже в python
  • компиляция в нативный код, только непонятно, зачем (возможно, чтобы Docker работал) 🙂

Возможно, Golang был создан в рамках конкурентной борьбы крупных корпораций, Google vs Sun/Oracle, за сердца разработчиков, но мы этого, скорее всего, никогда не узнаем 🙂 Очевидно, что создание «сильно упрощенной Java/C#» привлечет и уже привлекает толпы поклонников решения системных задач, но выиграет ли от этого индустрия — нам еще предстоит увидеть. Хотя Docker на Golang вот уже появился и перевернул мир в верном направлении. А еще объективная польза от Golang — это язык с низким уровнем вхождения и если нет времени изучать Java/C#, а нужно решить системную задачу, то самое то.

Интересно на этом фоне смотрится, конечно, Swift, c «более продвинутым» сборщиком мусора и свежими идеями. Но не всегда же разрабатывать под macOS.

Отключение ненужных параметров

луль

Если у вас совсем очень низкий FPS, и играть практически невозможно, то ставим всё на минимум и переходим к способам повышения FPS (следующий пункт)!

Если ваш ПК позволяет играть в Rust комфортно, но вы хотели бы отключить ненужные параметры, то отключаем Contact shadows, World reflections, Max shadow light, Parallax mapping, Max gibs, Terrain quality и Decor quality. Параметр Particle quality выставляем на максимум, а остальные уже регулируем «под себя». Таким образом вы снизите нагрузку, которую создают совершенно ненужные параметры!

Никому нельзя верить

Чего не стоит делать в Rust, если начали играть в 2021 году

Этот пункт частично противоречит предыдущему, но при этом он еще более важен. Прежде всего вам стоит забыть о том, что взаимодействие с другими игроками в многопользовательских проектах – это норма. Rust вообще не та игра, где нужно объединяться с незнакомыми людьми, чтобы вместе получить больше лута или ресурсов. Здесь вы можете рассчитывать только на себя, и если начнете доверять первому встречному игроку, то очень скоро поймете, почему этого нельзя делать. Особенно это касается товарищей с хорошей экипировкой, которых вы встретите на своем пути.

Дело в том, что в Rust каждый играет сам за себя, а опытные игроки очень часто обманывают новичков самыми разными способами. Незнакомец, который предложит побегать с ним по виртуальному миру и при этом будет носить броню заметно лучше вашей, скорей всего грифер. Это такой игрок, который при первой же удобной возможности просто вас убьет и заберет все вещи. Так что, начиная играть в Rust, никому не доверяйте!

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

Параметры HUD

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

Рекомендуем ознакомится с другими гайдами на популярные игры tattoo-mall.ru. Расскажем про секреты и хитрости, которые можно использовать в играх со своей выгодой. А также про полезные и интересные историй в видеоиграх.

  • Видимость : Полная
  • Масштаб : 60-100%
  • Непрозрачность : 80-100%
  • Индикатор положения : выключен
  • Индикатор инвентаря : выключен

Adblock
detector