LINUX.ORG.RU

Почему Discord сменил Go на Rust. Блог разработчика.

 , ,


3

5

В статье автор описывает успешный проект Discord, в котором Rust используется для потоковой обработки в Go Live и их Elixir NIFs’ сервере.

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

>>> Why Discord is switching from Go to Rust

★★☆☆

Проверено: Shaman007 ()
Последнее исправление: cetjs2 (всего исправлений: 1)

Ответ на: комментарий от ergo

ребята даже не попытались заниматься реюзом объектов

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

ya-betmen ★★★★★
()
Ответ на: комментарий от Siborgium

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

mx__ ★★★★★
()
Ответ на: комментарий от ya-betmen

это нормально для языков с гц. процесс разбора мусора становится накладным только при больших объемах этого мусора. во всяком случае это так с го. за яву ничего сказать не могу, нет опыта разработки на этом языке.

ergo ★★★
()
Ответ на: комментарий от Legioner

С виду go взлетел сильнее. Ну и rust трогать как-то вообще нет желания.

Выглядит как какой-то перл-стайл. Типичный проект имеет зависимостей как поделие на nodejs, среди них обязательно будет что-нибудь, что требует найтли. Собирается это все естественно триллиард лет. Таргеты вроде как есть, но жиже чем у C/C++ (ну, это конечно очевидно, но для типа системного языка как-то так себе). Таер1 вообще куцый. Поддержки каких-нибудь WindowsXP можно и не ждать. В общем - слабо понятно, зачем это всё нужно. Для переносимости/совместимости с системным говном мамонта все равно придется выбирать С/С++, для модных-молодеждных поделок часто и python не тормозной, чего уж о говорить о Go.

В общем, ниша конечно у него есть, но..

vasily_pupkin ★★★★★
()
Ответ на: комментарий от ergo

У Go именно Garbage Collector или обычный Reference Counter?

У этих подходов есть отличия. GC работает в отдельном потоке. И может убирать мусор не сразу, чтобы не тормозить приложение. Разные стратегии есть.

Ref Counter работает в потоке приложения. Там сам компилятор вставляет код проверки каждой переменной. Если ссылок нет, то память освобождается. Прямо в том же месте, где число ссылок изменилось.

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

Примеры второго - Swift.

hibou ★★★★★
()

Пацаны из дискорда конечно храбрые. Сначала Elixir начали шатать, теперь вот Rust, но в 2k21 такое поведение чревато. Нужно слушать корпорации добра и писать только на чём скажут.

P.S. Читаю сообщения ваши и в который раз убеждаюсь, что Rust отобрал нишу «языка для веселья» у Perl’а :3

perl5_guy ★★★★★
()
Ответ на: комментарий от qulinxao3

И не говори мне, что у гугла нет денег на нормальных C++ программистов.

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

некоторые думают что зависит обратной зависимостью?

Кстати, часто - да.

Есть такая способность - очковтирательство. Люди, которые на этом специализируются, как правило стекаются на проекты, где много денег. Знаю лично несколько примеров такого эффекта.

Kroz ★★★★★
()
Ответ на: комментарий от Cergoo

В го самый передовой GC

Полная чушь. В go убогий mark-and-sweep.

которому завидуют все остальные ЯП с GC

Полная чушь. GC различаются по своему предназначению, и уже поэтому завидовать ему могут далеко не все. Хотя у Go действительно неплохой GC (исходя из обозначенных целей), он абсолютно ненастраиваемый. За примерами других GC, которые как минимум не хуже Go’шного советую почитать про новые OpenJDK’шные GC, в частности, ZGC и Shenandoah GC.

Siborgium ★★★★★
()
Ответ на: комментарий от hibou

Ты в числе «счастливчиков». Даже если половину всего, что разрабатывается в России, портировать на эльбрус, мировые тренды это вряд ли изменит.

А ваша реализация на Go не прошла даром. Как минимум вы, опробировали систему на Go (что могло быть сложнее/затратнее с C++). Теперь вы не начинаете с чистого листа. А чел тот получил опыт разработки на Go, который и вашей команде может пригодится, когда/если Go портируют на эльбрус.

seiken ★★★★★
()
Ответ на: комментарий от hibou

Лисп - это же интерпретатор? Или я ошибаюсь?

Это язык программирования.

hummer
()

почему это кому-то вообще должно быть интересно?

sartakov
()
Ответ на: комментарий от mx__

Я думаю, опенсорс есть опенсорс. TM это про название. Ну назови не Go, а Poshel.

Legioner ★★★★★
()
Ответ на: комментарий от vasily_pupkin

С виду go взлетел сильнее.

А C# и Swift ещё сильней. С такими-то корпорациями за спиной. Но к качеству языков это не имеет отношения, это всё от маркетинга.

Ну и rust трогать как-то вообще нет желания.

Никто же не заставляет. У тебя нет, у других есть.

Выглядит как какой-то перл-стайл.

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

Типичный проект имеет зависимостей как поделие на nodejs

Почему это плохо? Ты против переиспользования кода? У JS я вижу ровно одну проблему: стандартная библиотека слишком куцая, отчего рождаются left-pad-ы. У Rust этой проблемы я не замечал, все зависимости нужны и важны.

среди них обязательно будет что-нибудь, что требует найтли.

Ну вообще-то есть проекты, принципиально работающие только на stable. Хотя я ничего страшного в найтли не вижу, ну найтли и найтли. Код в Rust качественный, на баг наскочить шансов очень мало.

Собирается это все естественно триллиард лет.

Если ты про полную пересборку - какая разница, ну попей кофе. А так - скорость сборки, конечно, не сильная сторона Rust, тут согласен. Хотелось бы чего-то побыстрей для разработки.

Таргеты вроде как есть, но жиже чем у C/C++ (ну, это конечно очевидно, но для типа системного языка как-то так себе). Таер1 вообще куцый.

Проблемы молодости, кмк. Со временем будет лучше.

Поддержки каких-нибудь WindowsXP можно и не ждать.

Ну она ничем принципиально не отличается от Windows 10. Если тебе очень надо, уверен, это можно сделать самому за разумное время. А ждать поддержки устаревшей и снятой с поддержки Microsoft-ом ОС в новом софте как-то странно. Даже Visual Studio поддерживает XP только в каком-то особом тулчейне режима совместимости, насколько я помню, а что раньше, по-моему и вовсе не поддерживает.

В общем - слабо понятно, зачем это всё нужно.

Слабо понятно, зачем нужна поддержка Windows XP или каких-нибудь Itanium-ов. А большинство как бы пользуется современными ОС на мейнстримовых платформах и твоих проблем не понимает. Ну не запустится сервер Discord-а на Itanium/HPUX. Да как бы никто и не пытался, всем нужен x64 в AWS, через пару лет всем будет нужен ARM64. Вот и посмотри, как оперативно добавили ARM64 в Rust. Который действительно нужен многим.

Для переносимости/совместимости с системным говном мамонта все равно придется выбирать С/С++

Не поспоришь.

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

Python - динамическая убогость. Go - статическая убогость. Я не знаю, как можно его сравнивать с красивым Rust-ом. Я бы сказал, что основной конкурент Rust это что-то вроде C#, в котором и языковых возможностей хватает для приятной жизни и GC избавляет от управления памятью. Но у Rust своя прелесть - писать код, который работает почти максимально быстро это просто приятно. Ну некоторым людям по крайней мере.

Legioner ★★★★★
()
Последнее исправление: Legioner (всего исправлений: 1)
Ответ на: комментарий от upcFrost

Разумеется не будет. Будет проблема с задержкой на сеть, и куда более жёсткая

Ерунда это всё. Проектируй так, чтобы не было. JWT там всякие. И прочее.

  1. Запрос прилетает в мололит. Декодирует JWT. Обрабатывает его в рамках своего домена.
  2. Запрос прилетает в микросервис. Декодирует JWT. Обрабатывет его в рамках своего домена.

Большая разница. И самое главное. Что у них и так там микросервисы. Только почему-то резиновые, а не нормальные поцанские.

kostyarin_ ★★
()
Ответ на: комментарий от ixrws

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

Да зачем. Микросервисы это вообще бомба. DDD – это отличный подход. Нет никаких проблем с задержкой, если проектировать грамотно. Разумеется, что просто распиленное на микросервисы приложение так и будет тормозить. Т.к. ожидает оно совсем другого в по своей изначальной природе.

Фишка в том, что приложение пиленное на домены – это уже нечто другое. Собствено и дизайна БД это тоже касается. Больше не сделаешь LEFT JOIN на полстраницы. И транзакции километровой. Вся ахритектура меняется. Я очень много слышал про распил монолита на микросервисы. И там же все эти пробелмы. На самом деле нужно не пилить монолит. А делать микросервисы. Причём распил идёт по бизне-логике, а не по логике программы. Бизнес-логика первична.

И объединение результатов точно так же делается по другому. Весь подход изначально другой. В этом и есть фишка.

kostyarin_ ★★
()
Ответ на: комментарий от kostyarin_

Ерунда это всё. Проектируй так, чтобы не было.

Как ты из микросервисов уберешь задержку на сеть? Ну кроме как их все на одну тачку засунуть. Это как бы физическое ограничение, если что.

Как бы можно параллелить запросы, обмазываться future и прочими, но для critical path ты ее не сможешь убрать вообще никак. Просто потому что сигналу нужно время чтоб дойти из точки А в точку Б

upcFrost ★★★★★
()
Ответ на: комментарий от Aceler

Выучить C++ несложно. Я делал это множество раз.

И ведь не смешно! А просто страшно.

Shadow ★★★★★
()
Ответ на: комментарий от Legioner

Моральный ответ - если бракодел, то не должен. Если человек уважает себя и окружающих, то должен.

Т.е. ты имеешь ввиду торговаться по сроками и цене, до оптимального варианта, или отказаться делать это совсем?

kostyarin_ ★★
()
Ответ на: комментарий от Legioner

всё становится только быстрей

React.js жи!
Ещё AngularJS с версии 1.3 и до последних 1.xx становился только тормознее (не, в чём-то быстрее, конечно...)

Shadow ★★★★★
()
Ответ на: комментарий от upcFrost

Как ты из микросервисов уберешь задержку на сеть? Ну кроме как их все на одну тачку засунуть. Это как бы физическое ограничение, если что.

Ну смотри. Классика – хранение сессии. Нужно обновить имя пользователя.

  1. Запрос.
  2. Заглянуть в ДБ, найти сессию.
  3. Проверить сессию.
  4. Обновить имя пользователя.

И микросервисы

  1. Запрос c JWT прилетает сразу в микросервис users.
  2. JWT раскодируется и проверяется.
  3. Имя пользователя обновляется.

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

kostyarin_ ★★
()
Ответ на: комментарий от hobbit

Skype же. (А первые версии вообще на Delphi были.)

Запили штуку, которая нужна всем, и которой нет – это одно. И пытаться подвинуть эту штуку – задча на порядок сложнее. Прикол в том, что для этого используются такие приёмы как

  • Go/Rust
  • Электрон
  • Нет подалвени эха*

Полгагаю, если бы ребята пислаи на C++ то ничего бы не вышло.

* С колонками Discord бесполезен, в отличии от Скайпа. И это не мешает им пиариться, что де процессорного времени в два раза меньше жрёт. Хотя для стриммеров с их гарнитурами и подавление эха не нужно.

kostyarin_ ★★
()
Ответ на: комментарий от kostyarin_

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

Также большой вопрос стоит ли использовать микросервисы для больших систем, даже если вы проектируете такое с нуля. Лучше всё таки прикинуть нужно ли оно вообще, в каких частях системы нужно. И да, накладные расходы будут, и чем больше взаимодействий, тем больше будут расходов. В том числе на сопровождение, разворачивание и обновление всего этого. Не зря же народ наплодил так много средств для оркестровки:)

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

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

ixrws ★★★
()
Ответ на: комментарий от vertexua

Счётчик ссылок(Smart Pointer) добавляет хоть и небольщую но допольниную процедуру подсчёта этих самых ссылок.

grim ★★☆☆
() автор топика
Ответ на: комментарий от grim

Если в цикле заходить и выходить, создавая копию, тогда да.

Но обычно делят разные «компоненты» системы (всякие «менежеры», «контоллеры» или кеши), которые после начального dependency injection просто висят в памяти. Обычно важно то что потом доступ по указателю не требует проверок.

Другое дело конечно weak pointers, их нужно обычно прокачать до shared при каждом доступе

А unique pointer чем не smart pointer. Хочешь говорить от счетчиках, то тут compile-time счетик до одного. Полностью стирается компилятором. Ну или должен стираться, а так мало ли че там за баги в компиляторах (или стандартах)

vertexua ★★★★★
()
Последнее исправление: vertexua (всего исправлений: 1)
Ответ на: комментарий от grim

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

pavlick ★★
()
Ответ на: комментарий от Legioner

Почему это плохо? Ты против переиспользования кода? У JS я вижу ровно одну проблему: стандартная библиотека слишком куцая, отчего рождаются left-pad-ы. У Rust этой проблемы я не замечал, все зависимости нужны и важны.

Мне сложно сходу принять решение хорошо это или плохо, но на мой взгляд это говорит об отсутствии какого-то стандартного набора для решения стандартных проблем. Например, если мне сходу нужно гуглить, какую либу для http использовать, или суммарно фетчить 300+ пакетов для небольшого веб сервиса – явно что-то пошло не туда.

Слабо понятно, зачем нужна поддержка Windows XP или каких-нибудь Itanium-ов.

Если язык позиционирует себя как системный, то желательно что бы примитивы и решения на нем написанные могли быть использованы максимально широко. Взять какой-нибудь curl или openssl. Они написаны на богомерзком C, но они есть вот просто /везде/. В т.ч. и в виде биндингов к расту (как же так!).

Ну не запустится сервер Discord-а на Itanium/HPUX. Ну вот и остаётся ниша локальных изделий, изделий на волне хайпа, и движка браузера )

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

Красивым? Макросы, аттрибуты, знаки препинания в коде.. Дело вкуса конечно.

vasily_pupkin ★★★★★
()
Ответ на: комментарий от hibou

Вообще не понимаю

Ты прав. Не понимаешь.

Современный С++

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

Насколько сильно ты понимаешь на каком уровне все эти проблемы решаются например в Rust? Например компилятор управляя памятью понимает даже многопоточность.

vertexua ★★★★★
()
Ответ на: комментарий от vasily_pupkin

Ну то есть знаки препинания есть и в Go, понятно. А так - да, в Rust легче написать нечитаемую хрень, если есть желание. Приведенный тобой фрагмент хорошо демонстрирует такое желание (хотя он синтаксически некорректен, ЕМНИП).

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от tailgunner

Да, он не корректен. Это пример знаков, о которых идет речь, а не код (%

Все это конечно дело вкуса. Но раз уж кто-то говорит что это красиво..

vasily_pupkin ★★★★★
()
Ответ на: комментарий от vertexua

Т.е. весь вопрос опять к программистам? Которые не хотят думать?

Когда компилятор управляет памятью - это всегда будут накладные расходы.

hibou ★★★★★
()
Ответ на: комментарий от vasily_pupkin

Но раз уж кто-то говорит что это красиво..

Кто-то говорил о коде, а ты дал бессмысленную последовательность знаков. И вот всё у вас так.

tailgunner ★★★★★
()
Ответ на: комментарий от hibou

Когда компилятор управляет памятью - это всегда будут накладные расходы.

Вопрос только в том, что когда памятью пытается управлять компилятор Си++, эти расходы неоправданно велики.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Ну вот нашел от балды пару примеров с осмысленной последовательностью знаков. Типичный код, первый попавшийся за 5 минут.

#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for Signature {
    fn deserialize<D: de::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        struct ByteArrayVisitor;

        impl<'de> de::Visitor<'de> for ByteArrayVisitor {
            type Value = [u8; SIGNATURE_LENGTH];

            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
                formatter.write_str("bytestring of length 64")
            }
...

fn find_valid_key_handles<'a, F>(
    app_ids: &'a [crate::AppId],
    key_handles: &'a [crate::KeyHandle],
    mut is_valid: F,
) -> (&'a crate::AppId, Vec<&'a crate::KeyHandle>)
where
    F: FnMut(&Vec<u8>, &crate::KeyHandle) -> bool,
{
    // Try all given app_ids in order.
    for app_id in app_ids {
        // Find all valid key handles for the current app_id.
        let valid_handles = key_handles
            .iter()
            .filter(|key_handle| is_valid(app_id, key_handle))
            .collect::<Vec<_>>();
...
vasily_pupkin ★★★★★
()
Ответ на: комментарий от hibou

Т.е. весь вопрос опять к программистам? Которые не хотят думать?

Им нужно думать всегда. Но главное о чем. Например в большинстве своего кода не хочется думать о расположении данных в регистрах процессора. Но так же и ассемблер программист скорее всего сопротивлялся появлению С, мол что, теперь думать не прийдется. Хотя ему говорили что язык сам по себе не забирает производительности (хотя ранняя имплементация могла). Теперь что? Компиляторы С лучше практически любого машинного кода написаного вручную

Когда компилятор управляет памятью - это всегда будут накладные расходы.

С чего бы. Это все консервативные стреотипы из 90х. Чем больше ешь кактус, тем быстрее твой язык.

Дак в том то и дело что шумиха поднялась. Впервые сделали язык где нет - помощь компилятора в ноль вытирается в результирующем коде. До этого в D было не так, в Go и подавно. А Rust оп, и сделали zero cost abstractions. Не сборщики мусора, не какие-то managed runtimes вроде Java/.NET. Просто С++ сделаный по принципу «а теперь выйди и зайди нормально»

И еще крутая фича - язык обучает тебя программировать в целом. То что тебе Rust просто не позволяет приходится обходить путем редизайна кода на более понятный. Но потом ту же структуру можно повторить в С++. Компилятор заставляет делать вещи и заставляет делать хорошие вещи. Постоянно напоминает что владение чем-то непонятно и не дает написать такой код.

vertexua ★★★★★
()
Последнее исправление: vertexua (всего исправлений: 4)
Ответ на: комментарий от vasily_pupkin

Типичный код

По крайней мере, это действительно код. Хотя насчет «типичности» ты опять. В любом случае, если бы ты привел эквивалентный код на, например, Go, было бы о чем говорить. А так - тупо демагогия.

tailgunner ★★★★★
()
Ответ на: комментарий от vertexua

Когда компилятор управляет памятью - это всегда будут накладные расходы.

С чего бы.

Накладные расходы бывают разные. Например, если сборки мусора нет (как в Rust), приходится больше думать о проектировании структур данных. Это тоже накладные расходы.

tailgunner ★★★★★
()
Ответ на: комментарий от ya-betmen

Пулы обьектов кстати это не совсем уникальная проблема в Java. В том же С, С++, Rust можно получить много профитов через arena allocation. Потом вообще не освобождать память для каждого указателья по отдельности, а просто инвалидируя арену. Rust еще чисто на этапе компиляции не даст убить арену пока есть хоть одна ссылка на внутренности. Это вот как раз редкий пример кода где в библиотеке прийдется поплясать с лайфтаймами и unsafe. Зато со стороны пользователя библиотеки все будет очень строго

vertexua ★★★★★
()
Последнее исправление: vertexua (всего исправлений: 3)
Ответ на: комментарий от tailgunner

приходится больше думать

Тут вот товарищ наоборот ругается что как это теперь программисты не будут думать о памяти, как деды делали.

Все равно приходится о чем-то думать. Смотря когда и о чем. Я бы наверное таки подумал о структурах

vertexua ★★★★★
()
Ответ на: комментарий от vertexua

Все равно приходится о чем-то думать. Смотря когда и о чем. Я бы наверное таки подумал о структурах

В Rust приходится думать именно о вопросах, которых в принципе нет в языках с GC (вдобавок к собственно проектированию структур данных). Хотя в Си++ то же самое, только хуже.

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от tailgunner

В Rust приходится думать именно о вопросах, которых в принципе нет в языках с GC

Кстати. Вроде бы еще не сделали GC-based вариант Rust. Чтобы владение указывать не нужно было, как в Java/Go, но чтобы была защита встроеная в компилятор от например проблем с многопоточностью. Легко можно порвать указатель, не защитить что-то нормальной синхронизацией и делиться незащищенными мутабельными структурами. Разве что языки с системами актеров дают такое, но это уже прямо совсем другая сематика.

vertexua ★★★★★
()
Последнее исправление: vertexua (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.