Pull to refresh

Comments 92

цели: ... повышения безопасности

Если со сравнением производительности вроде всё ясно. То как сравнивали безопасность? По количеству найденных багов fazzing тестами?

Я думаю, скоро начнутся новости типа. В библиотеке x переписанной на rust, найдена ошибка, уязвимость и т.д

В общей сложности наша команда из 3 разработчиков затратила более 20 человеко-месяцев усилий.

Аминь. Почти два года жизни было затрачено на переписывание, уже готового кода. Что бы он был переписан...

Ржавчина все новые площади охватывает.

Почти два года жизни

Да не, - почти стандартные 9 месяцев на 1 чела.

В общей сложности наша команда из 3 разработчиков затратила более 20 человеко-месяцев усилий.

Аминь. Почти два года жизни было затрачено на переписывание, уже готового кода. Что бы он был переписан...

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

Да. Первый раз ткнул, появилась ошибка. Ткнул во второй раз опубликовалось. Но появилось уже два сообщения.

А я думал вы переписали комментарий

И это только первый этап, который в результате дал минус 6% перфа. Дальше будет оптимизация (неясно сколько времени займёт) и самое главное - синк кода на Rust с изменениями в оригинальном коде. А это почти бесконечный процесс. Это должно быть очень нужно, если за такое взялись.

Надо было один раз потратить время на C-to-R конвертер и переписывать код автоматически и масшабно, а ошибки пусть нейросеть разгребает, всяко ей проще подкручивать, чем синтезировать. Тестов насыпать и всё, что завалилось снова на вход нейросети! Вкалывают роботы!

Интересно, а можно было переписать с "небезопасного С" на более безопасный С(с соблюдением современных стандартов, рекомендаций, использованием стат. анализаторов и т.д.). Уверен, что прирост в производительности был бы измерим. А вот на сколько одно "безопаснее" другого, тут был бы вопрос. Да и времени наверняка бы меньше ушло.

Интересно, а можно было переписать с "небезопасного С" на более безопасный С(с соблюдением современных стандартов, рекомендаций, использованием стат. анализаторов и т.д.)

Проект dav1d "относительно" свежий по меркам выхода сишных стандартов (2018г.). Да, стандарт там C99 (только без VLA и некоторых примочек), C11 для потоков и современный POSIX. Смысла в тогда вышедшем С18 они при разработке, наверное, не видели.

Учитывая, что целью поставили кроссплатформенность и достижение максимально возможной скорости, чтобы преодолеть временное отсутствие аппаратного декодера AV1 (он уже появился 3-4 года назад если что), думаю, им новый C23 не подойдет, т.к. он до сих пор не опубликован и, соответственно, не так широко поддерживается. Да и насколько быстрее будет код на C23, это другой вопрос.

Я скорее имел ввиду полный рефакторинг, нежели именно переход на новый стандарт С, да это мало что даст. Быстрее библиотека стала работать точно не из-за того, что Rust быстрее С. А так получается мы просто получили копию библиотеки но вместо С тут Rust. Окей, Раст гарантирует нам, что мы не отстрелом себе правую ногу, но по всем остальным конечностям все ещё можно стрелять. Так что если бы это была новая библиотека, без обратной совместимости и т.д. это дело было бы однозначно хорошее, но такая библиотека уже есть. А так, какой смысл в точно такой же либе, но без того комьюнити и поддержки, что делает оригинал?

Я скорее имел ввиду полный рефакторинг, нежели именно переход на новый стандарт С

Видимо, я просто не так понял.

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

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

 Быстрее библиотека стала работать точно не из-за того, что Rust быстрее С

А она и не стала)

Аппаратный декодер появляется в течении года после финализации стандарта. AV1 завершен гораздо ранее 3-4 лет, 3 года это VVC.

Лично мне интереснее было бы посмотреть на С++-версию, без использования C-style, но с использованием всех плюсовых механизмов безопасности и читаемости. Как велика была бы просадка в производительности (ведь истые сишники любят пугать ею).

Не понятно, в чем проблема. Они написали обработку для видео? Так ведь давно есть klite coded pack и даже vlc, где все это есть. А еще каждый телефон умеет его записывать и проигрывать

Более того, на сколько я понял из статьи они переписали все as is, без погружения в детали алгоритмов и т.д. так что если где-то были логические баги, есть вероятность, что они остались и в новой реализации.

Ну и как принято - добавили немножко новых, своих... Свой, так сказать, вклад внесли. Может я и не прав, но - это уже больше правилом стало.

Есть же xiph/rav1e, который изначально был на rust, зачем нужен ещё и копипаст сишного кодека?

Всё дело в последней букве в названии библиотеки.

Какая то бесполезная работа была сделана, взять рабочую си библиотеку и заставить ее работать на расте. Фанатикам раста главное написать о безопасности и производительности и написать при этом кучу unsafe кода. Писать нужно новый код, а старый просто переносить в виде врапперов, либо делать сразу на расте с нуля, если позволяют ресурсы, тогда можно заявлять о повышении безопасности/производительности

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

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

если продолжить оптимизацию и доработку порта на Rust, то он сможет уверенно соперничать с реализацией на С во всех ситуациях, попутно обеспечивая безопасность памяти.

Как оно может соперничать, если не переделывать логику алгоритмов. То что Rust безопаснее не может быть без компенсации этого скоростью. Дополнительные проверки все равно будет подтормаживать. Как надоело слышать «производительнее С». Производительнее Си только машинный код, даже не llvm.

Производительнее Си только машинный код, даже не llvm.

Это как? Си же компилируется в машинный код тем же llvm. Можете раскрыть что вы имели ввиду? Ассемблер? Так код на ASM не дает гарантий, что он будет быстрее оптимизаций C компилятора.

То что Rust безопаснее не может быть без компенсации этого скоростью.

Та же проверка типов. Повышает безопасность, в рантайме никак не влияет на скорость. Влияет только на время компиляции.

В rust же все эти многочисленные unwrap/expect/? разворачиваются в дополнительные проверки, которые повышают безопасность за счет производительности.

Вы так пишете, как будто на Си нет никаких проверок ошибок. А если и правда нет - нафиг такой код, даже если он "быстрый".

Вопрос к кодеру. Вылет за пределы это всегда ошибка в алгоритме. Если это декодер видео то там все должно быть детерминировано.

Не только. Ещё бывает ошибка во входных данных - испорченный видео поток напр

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

Не знаю си, но уверен что навязываемых проверок в си нет. Верим "массив не будет пуст и можно смело брать элемент" - и можно и не проверять. Rust же заставит обработать вероятную ситуацию, тем самым добавив лишние if.

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

Судя по количеству ошибок в сишном коде вариант "мамой клянусь тут ошибок нет" работает не очень.

В С проверок нет, это лежит полностью на программисте.

В Rust проверки на каждый чих будут только если вы совсем не задумываетесь о производительность. Например:

  1. fn print(arr: &[u8]) { println!("{}", arr[3]); }
    Здесь скорее всего будет проверка если функция не заинлайнится.

  2. fn print(arr: &[u8]) {
    let arr2 = &arr[2..5];
    println!("{} {}", arr2[0], arr2[2]);
    }
    Здесь компилятор уберет проверки при обращении к arr2 по индексам от 0 до 2.

  3. fn print(arr: &[u8]) {
    for i in arr.len() {
    println!("{}", arr[i]);
    }
    }

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

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

Что касается unwrap/expect, то expect вызовет панику, и на быстродействие пофиг. А unwrap в любом случае должен проверять, это полностью аналогично проверкам в С на null, и от них никуда не деться.

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

Например, вот такой кусочек не оптимизировался до rust 1.73, причём проверки оставались для двух доступов

pub fn foo(a: &[i32], b: &[i32]) -> i32 {
    let len = a.len().min(b.len());
    let mut r = 0;
    for i in 0..len {
        r = r * a[i] + b[i];
    }
    r
}

Более свежий я не использовал, но уверен, что таких случаев там остаётся ещё масса.

P.S. Да, в этом случае можно было использовать итераторы, но там где я на это наткнулся - было нельзя.

К этой теме еще стоит добавить, что как я понял borrow checker не ходит вглуб вызовов функций. Соответственно если в алгоритме встречаются вызовы функций, пусть даже заинлайненые, то доказательство выкидывания проверок все равно будет страдать.
Поправьте если ошибаюсь.

Во первых borrow checker не имеет отношения к проверкам границ. Во вторых borrow checkerу это и не нужно - он полагается на сигнатуры функций/структур, чтобы проверить все свои правила.

Это я понимаю, он проверяет нечто другое относящееся к языку, а не скрытым доказательствам. Я просто предположил что раз не ходит он - то не ходит и этот доказывальщик. Вопрос на каком уровне он реализован в надстройке llvm или внедрен в саму llvm. Если внедрен - то должно помочь -C linker-plugin-lto.
Я потому и спрашиваю, вдруг кто уже порэксперементировал. Лично я пробовал очень давно, и там даже в одной единице трансляции были проблемы.

Если ваш пример переписать вот так, то остается ровно 2 лишние проверки. Ну и есть большая вероятность,что будущие компиляторы их устранят тоже.

pub fn foo(a: &[i32], b: &[i32]) -> i32 {
let len = a.len().min(b.len());
let a1 = a[..len];
let b1 = b[..len];
let mut r = 0;
for i in 0..len {
r = r * a1[i] + b1[i];
}
r
}

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

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

struct Holder {    
  data: [u8; 1024]
}

impl Holder {
  fn some_check(&self, u: u8) -> bool {
    self.data.contains(&u)
  }

  fn index(&mut self) {
    for i in 0..self.data.len() {
      if self.some_check(self.data[i]) {
        self.data[i] = 0;
      }
    }
  }

   fn iter(&mut self) {
    for num in &mut self.data {
      if self.some_check(*num) {
        *num = 0;
      }
    
    }
  }
}

Метод с итератором не может одновременно взять ссылку на self и оставить ссылку на массив в итераторе

Согласен, текущая реализация итераторов такое не позволяет (из-за возможной инвалидации итератора). Но такие алгоритмы обычно итак пишут под unsafe в библиотеках. В прикладном коде не было пока необходимости.

Еще до выпуска 1.0 была идея у ссылок отдельно задавать мутабельность содержимого, и отдельно мутабельность самой ссылки. Можно было бы брать одну мутабельную ссылку на содержимое (но readonly саму ссылку) и несколько немутабельных на содержимое одновременно. Жаль что отказались, хотя синтаксис был бы сложнее.

Можете раскрыть что вы имели ввиду?

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

код на ASM не дает гарантий, что он будет быстрее оптимизаций C компилятора

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

Это как? Си же компилируется в машинный код тем же llvm.

Да, почему же. Это только с clang-ом пришло.

ак код на ASM не дает гарантий, что он будет быстрее оптимизаций C компилятора.

В принципе внизу ответили :) Я имею ввиду, что вручную написанный код на ASM точно не будет ограничен сверху ничем, связанным с кроссплатформиерностью и ограниченностью знаний/алгоритмов компилятора.

Действительно, возможно с некоторой вероятностью комплиятор Rust что-то и применит из ряда оптимизирующего, может даже лучше, чем С. Однако, в самих доках написано про boundary checks, borrow checks именно в райнтайме. С учетом их количества в типичном коде, это будет бить, и с наибольшей вероятностью либо не изменит производительность, либо ухудшит.

Ну и в целом Rust выразительнее Си, можно более высокоуровневые конструкции городить. Я сомневаюсь, что люди будут заниматься аскетизмом и не пользоваться этим преимуществом, что опять ударит по производительности, но увеличит продолжительность жизни программиста :)

Ничего плохого в этом не вижу, станет меньше seg fault, может ошибку найдут где-то, может улучшат что-то. Однако буду бить по столу и брюзжать слюной когда снова увижу "Этот язык быстрее С", пока не докажут, что новый компилятор устраняет фатальный недостаток (или делает мега-оптимизацию с учетом AXV и SSE и выравниванием памяти и чего там еще...) внутри сгенерированного кода llvm/asm по сравнению с clang/gcc.

увеличит продолжительность жизни программиста :)

Вот это так 100%!!

Возможности оптимизации во многом зависят от того, что знает о коде компилятор. Может оказаться так, что в Rust больше возможностей дать компилятору подсказку (либо же это получается косвенным образом, исходя из строгости языка), тем самым позволив ему создать более шустрый машинный код.

Но зачастую сделать такие подсказки без тщательного изучения алгоритма непросто.

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

Ага, потому в новый C++ завезли assume.

Угу, и тридцати лет не прошло с тех пор, как его стали завозить в популярные коммерческие компиляторы. Мгновение на фоне вечности. :)

Комитет отбивался, как мог - это ж новый источник UB на ровном месте :)

С чего бы вдруг? Если компилятор опасается, что его обманут, он может в отладочном режиме вставлять код для вычисления выражения и проверки результата, сочетая assume и assert. У меня макрос Assert так раскрывается с незапамятных времен.

То компилятор, а то абстрактная машина - и увы, другого решения при сохранении быстродействия (то бишь без проверок), кроме как UB, тут действительно не просматривается.

Даже если проверки вставлять только в отладочно-тестовых сборках, при адекватном тестировании вероятность UB понижается радикально.

Конечно, предельная оптимизация вообще должна подразумевать кучу аспектов:

  • Заточенность на определённую аппаратную платформу, причём именно платформу целиком, не только процессор — так как, например, разные планки памяти могут иметь разные характеристики, соответственно, оптимальный код может отличаться (пусть это и редкий случай). Ещё надо учитывать микроархитектуру ядра, на котором выполняется программа — особенно актуально на ARM и x86, начиная с Alder Lake

  • Заточенность на входные данные — если они не совсем случайные (а это большинство кейсов), то как правило, здесь тоже можно разгуляться — branch prediction, префетчи, оптимальная глубина разворачивания циклов, разные ветви кода для разных кейсов и так далее

  • Входные данные могут меняться со временем, и это тоже надо учитывать (нужен JIT?)

Как-то раз удалось, почти случайно, написать на Ассемблере код, который работал на E-ядрах (тех самых, которые так не любят) i7-13700H как минимум на 70% быстрее, чем любая вариация машинного кода, сгенерированная GCC / Clang / oneAPI DPC++ с различными сочетаниями оптимизирующих флагов и PGO (как компиляторным, так и с LLVM BOLT), причём работало на те же 70% быстрее даже чем при запуске на P-ядре при равной частоте.

Немного таблиц из других экспериментов, без оптимизации на Ассемблере

Числа в ячейках — время работы в секундах.

Программа на проверку гипотезы Коллатца до определённого N:

Сортировка пузырьком:

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

непосредственно машинный код можно написать любой, а компилятор в состоянии породить только ограниченное подмножество вариантов

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

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

Правильное название статьи: занимаемся ху....

Не кому ваш раст не нужен это бесполезный не до С язык

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

Но, как человек писавший на Си и изучающий Rust, могу сказать, что новый проект начну на Rust-е.

Более того, в старых проектах, уж коли доведётся модули зарефакторить, то перепишу на Rust.

Вопрос не в тему: ваш ник, - Slogan же мужского рода? А у вас Die Slogan. Почему?

Это был временный ник, который я так и не нашёл, как поменять на Хабре

Ну почему бесполезный? Вполне нормальный, со своими ньюансами и заморочками. И для быстрой разработки более удобный. Для сильно замороченного остается C/C++ (для особой упертости - assembler language, - сам применял пару лет назад на ARM-е).

Вон выше тоже чел написал свой вердикт. И я вполне его понимаю.

А вот ответьте мне, чем Rust удобнее для быстрой разработки? Я вот с его убер-жёсткой структурой постоянно мучился.

Така я до сих пор (я типа начинающий, ну по крайней мере в сравнении со строкм в C)... Но все-же он несколько быстрее позволяет получить результат на непростых задачах. Да и на простых тоже. И в некоторых случаях его жеская типизация позволяет упростить отладку. Хотя и режет возможности... Ну и никто не говорит что он простой, в общем-то. А там - каждому свое... На вкус и цвет все люди разные..

Для быстрой разработки, например небольшой консольной утилиты, которая парсит JSON-ы и складывает в Oracle DB.

На Си нам потребуется:

  1. Нужно поискать, где вы подключали похожие либы с помощью autoconf, cmake, meson, SCons(мы ведь не будем заново jansson писать).
    Ну и пошаманить с ними, открыть документацию, само собой.

  2. Если пишите под винду, там есть Visual C++ и вопрос с cmake-ами снимается, но ваша функция main выглядит примерно так. Вроде бы на Си пишите, а кажется, что и не на Си:

    DWORD __cdecl wmain(void) {     LPCWSTR str = L"Value";     return 0; }

  3. Если работаем с Oracle, то нужен Pro*C. На известном ресурсе посвященном Ораклу "Ask Tom", в вопросе про Pro*C адепт Oracle пишет:

    I use pro*c only when I cannot accomplish the task efficiently in PLSQL or SQL. In 9i, with external tables, merge, pipelined functions -- I'm very very hard pressed to find a reason to use C.

    Если вы не знаете что такое Pro*C, то вам очень повезло. Там нет проверки синтаксиса, а для компиляции cc вас не выручит, компилить такие файлы следует своей утилитой.

    Добро пожаловать в АД

    И это для одно поточного приложения, если у нас несколько потоков, то нам нужен контекст, и такой "элегантный код"


В моём опыте на Си, всегда присутствовало вот это: "ну на Си это написать — всё равно, что из пушки по воробьям, там же ерундовая утилита какая-то".

И в результате кодовая база состоит наполовину из Си, наполовину из адского нагромождения тормозных скриптов на bash, awk, python.

Для быстрой разработки, например небольшой консольной утилиты, которая парсит JSON-ы и складывает в Oracle DB.

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

Я крайний раз делал такое на Delphi, который сейчас Embarcadero, вполне шустро парсил и мороки было меньше. Пайтон все-ж сильно медленнее.

Я согласен, все зависит от задачи, если нужно один небольшой json в минуту парсить это одно, если миллионы совсем другое или если размеры json-файлов гигабайты, а если еще сами файлы нужно получать из разных мест (сеть, шара, облако) и т.д.. Но в общем случае видится что данная задача перегнать json-ы в базу данных это типичная задача для скриптовых языков.

Ну, вот как раз в моем случае была сетка с 10 источниками и числом строчек, ну от 100 000 и выше. А разово и на 5 строчек - ну скрип.

складывает в Oracle DB

О... Когда-то приходилось, слава Богу, в однпоток. Если вам сейчас приходится - примите соболезнования. Про "спроси Тома" - тоже знакомо...

А зачем тут вообще Rust или тем более C? Один скрипт на Python или JS решит проблему раз в 10 быстрее.

Исходя из того, что мы уже определились, что пишем наше большое приложение на Си или Rust, в таких условиях дописывание маленькой сопутствующей утилиты всегда рискует перерасти в ад из кучи скриптов на bash, awk, python, etc.

Если работаем с Oracle, то нужен Pro*C. На известном ресурсе посвященном Ораклу "Ask Tom", в вопросе про Pro*C адепт Oracle пишет:

Много приходилось работать с ораклом ни когда не использовали Pro*c, если работали локально на сервере, находили oracle home из него загружали OCI библиотеку (dll/so) из нее собственно десяток функций, если удаленно то использовали динамические библиотеки из SDK.

Ну так у каждого свои грабли. Помнится, Oracle Call Interface - он только под винду вроде был?

Под линукс так же работает, те же сигнатуры функций, только название библиотеки другое.

Если бы меня спросили, на чём следует писать уровень взаимодействия с базой данной, то я бы отдал предпочтение C#, где без всяких лишних прокладок в виде OCI, с библиотекой размером 4 Мб обходятся.

Можете дать ссылку, где написано, что драйвера для Java/C# являются просто оберткой над OCI?
Потому что я на сайте Оракл только находил инфу о том, что это native драйвера

А чем оси не нативный? Для шарпа оси в зависимостях, в код итп не лез.

Тем, что не написан на JVM/.NET.

OCI или Oracle® Call Interface это старый интерфейс для Java/C#, когда работаешь в этих языках, вам нет необходимости ставить Oracle Instant Client и т.п. Также, нет необходимости ставить отдельный для Linux, отдельный для винды.

При подключении нативной для платформы библиотеки, конечный Docker образ приложения увеличивается на 4 Мб, вместо установки 121 Мб Basic Package.

Вообще-то, термин "нативный" как раз и означает что код не написан на .NET.. К написанным на .NET библиотекам применяется термин "управляемая" ("managed")/

На сайте Oracle написано, что они native. И magaged не применяется к коду на Java.

Зато native имеет одинаковый смысл что в Java, что в .NET

Про С понятно, но вот чем С++ тогда хуже?

Кто-то сказал: C это высокоуровневый ассемблер, C++ это высокоуровневый язык :)

Если приложение небольшое, то C++ избыточен, вы тащите за собой рантайм, без которого ничего работать не будет.

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

Сам C++ я побаиваюсь, знаю его в разрезе MFC. И это ничего не значит, если приложение будет написано на boost, stl. Я вынужден буду изучить и их.
Я ещё тут читал ахи-вздохи C++ программистов по поводу того, что иногда трудно угадать, как соптимизирует код компилятор, из этого выходило, что порой это рулетка. Короче, лично для меня, и без этого проблем хватает, есть множество других языков.

Понимаю позицию, но не до конца согласен. Рантайм можно обрезать очень сильно, если не тащить за собой тяжёлые библиотеки (включая местами стандартную). А что С++ позволяет стрелять себе в ногу более разнообразно, чем C - соглашусь.

Да, можно обрезать. В том же Arduino я пишу на C++, фактически, но не углубляюсь.

К тому же, например, под микроконтроллеры ESP32 я вместо С/С++ использовал бы Toit потому что компиляция не занимает 10 минут, можно очень быстро проверять на конечном устройстве. А вот если на тех же контроллерах потребуется создавать красивые интерфейсы, то я опять же возьму C/C++, потому что интерфейсы удобно создавать с помощью библиотеки LGVL.

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

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

То есть люди переписали "потенциально небезопасный" код на C в настолько же небезопасный код на Rust (цитирую: "мы сохраняем пространственную безопасность, потенциально компрометируя безопасность потоков"), но теперь будут говорить, что у них безопаснее?

Ассеиблера было больше ЛОК переписывать

Портируем декодер AV1 с С на Rust для повышения быстродействия и безопасности

Для сохранения быстродействия мы оставили в коде (небезопасные) нативные процедуры ассемблера, которые выполняют низкоуровневые операции декодирования

Sign up to leave a comment.