LINUX.ORG.RU

Правильно ли я пишу на Rust?

 , ,


1

7

Часто мелькает Rust и в новостях, и в темах. Решил попробовать переписать один тест с С на Rust. Для сравнения написал вариант и на C++. На Rust получилось в 4+ раза медленнее, чем на С и в 2+ раза медленнее, чем на C++. Есть подозрение, что я делаю что-то неправильно, но не знаю что. Помогите, пожалуйста, разобраться.

UPD. Мои цифры:

$ gcc c_v1.c -Ofast -march=native
$ ./a.out 3000
16.439091
-287.250083
$ g++ cpp_v2.cpp -Ofast -march=native
$ ./a.out 3000
31.3826
-287.25
$ rustc rust_v1.rs -C opt-level=3 -C target-cpu=native
$ ./rust_v1 3000
71.570172703s
-287.2500833333321
★★

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

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

Сравнивать нужно тогда вообще без оптимизаций

В GCC не все оптимизации отключаются, в Clang наверное тоже.

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

Я имел ввиду, что хотя бы их не включать явно. Но при желании можно и поотключать принудительно всё что можно. Только в обоих случаях останется вопрос что вообще сравнивается и самое важное «зачем»? Это будет равносильно сферическому коню в вакууме и неуловимо у Джо одновременно.

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

Что в его синтаксисе вырвиглазного, если сравнивать с каким-нибудь с++?

У C++ синтаксис уже привычен. А тут новый язык.

И есть же новые языки с нормальным синтаксисом - Kotlin, Swift.

anonymous
()
Ответ на: комментарий от grem

Но при желании можно и поотключать принудительно всё что можно

Сильно сомневаюсь, что у GCC и Clang можно отключить все оптимизации… Даже принудительно.

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

поотключать принудительно всё что можно

Очевидно, что то что нельзя отключить - не отключить. Но даже если можно было б, то вопрос о том, «что сравнивается в этом случае и как этот результат можно использовать в реальности?» останется.

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

И есть же новые языки с нормальным синтаксисом - Kotlin, Swift.

Свифт

func chooseStepFunction(backward: Bool) -> (Int) -> Int {
    func stepForward(input: Int) -> Int { return input + 1 }
    func stepBackward(input: Int) -> Int { return input - 1 }
    return backward ? stepBackward : stepForward
}
var currentValue = -4
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)

while currentValue != 0 {
    print("\(currentValue)... ")
    currentValue = moveNearerToZero(currentValue)
}
print("zero!")

Раст

fn choose_step_function(backward: bool) -> fn(i32) -> i32 {
    fn step_forward(input: i32) -> i32 { input + 1 }
    fn step_backward(input: i32) -> i32 { input - 1 }
    if backward { step_backward } else { step_forward }
}

let mut current_value = -4;
let move_nearer_to_zero = choose_step_function(current_value > 0);
    
while current_value != 0 {
    println!("{}... ", current_value);
    current_value = move_nearer_to_zero(current_value);
}
println!("zero!");
red75prim ★★★
()
Ответ на: комментарий от red75prim

Код на расте без лайфтаймов - это хелловорд! Низачёт.

Дайте развесистых структур, с контейнерами (собственными) и содержащие контейнеры (другие), а потом обработку всего этого на генериках.

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

Это был «чёрный пиар», отвечать не обязательно.

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

Ну так func вместо fn, Int вместо i32, var вместо let mut, явно видный return. Даже на таком коротком примере код читается проще.

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

Хех. Ничего, что в Свифте на каждом классе ARC? И они при каждом вызове функции атомарно инкрементируются и декрементируются, инкрементируются и декрементируются, инкреме..., ну и так далее.

red75prim ★★★
()
Последнее исправление: red75prim (всего исправлений: 2)

Используй встроенную функцию matmult в fortran и не мучайся. Матрицы там тоже есть из-короьки.

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

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

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

Но даже в этом мусорном примере, в котором бездарность пыталась скрывать все проблемы,

(Int) -> Int
fn(i32) -> i32

Здесь сразу можно заметить фундаментальную разницу. Раст-бездарности не осилил написать парсер.

return backward ? stepBackward : stepForward
if backward { step_backward } else { step_forward }

Здесь видно, как бездарности пытались выпиливать return, ведь иначе всё это говно бы разваливалось. Из-за этого у бездарной как всегда потекла семантику и её срочно нужно было пихать в ;. В итоге как всегда получилось неконсистентное говно.

println!(«{}... », current_value);
print(«\(currentValue)... »)

Здесь так же можно видеть фундаментальную разницу. В бездарном говне клоуны не осилил написать парсер, да и сам язык говно - пришлось пихать мусорные макросы, которые выглядат как мусор. В свифте же никакого мусора нет.

Далее, мы опять видим ворованную из пистона строку формата. В свифте же видно импрувнутые литералы.

chooseStepFunction(backward:

В свифте мы видим именованные аргументы.

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

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

Чувак, ну брось уже. Этот коммент как и другие скоро утечёт в /dev/null вместе со всем говном/мусором и прочей вкусовщиной.

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

Нет, просто ваше восприятие читабельности не эталон из палаты мер и весов.

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

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

У C++ синтаксис уже привычен. А тут новый язык.

Именно. Похоже, что когда говорят о «вырвиглазности» чаще всего подразумевают, именно что-то непривычно для себя, но это же не значит, что всё новое априори плохо.

И есть же новые языки с нормальным синтаксисом - Kotlin, Swift.

Моё мнение есть смысл сравнивать синтаксис когда языки предоставляют схожие возможности. Kotlin же по JVM, а нативная версия, вроде как, в разработке. У Swift принудительный подсчёт ссылок, да и тестах производительности он показывает себя не очень. Если хотите сравнить Kotlin и Swift с C, C++ и Rust, в теме описана задачка и много примеров реализации. Предложите свои варианты на этих языках, посмотрим.

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

улучшают читабельность

Это вы про бесполезный return? Ну ок.

Нет, просто ваше восприятие читабельности не эталон из палаты мер и весов.

Спасибо кеп.

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

Что в его синтаксисе вырвиглазного, если сравнивать с каким-нибудь с++?

У него нету синтаксиса, вообще. За примерами далеко ходить ненужно.

use std::{env, time::Instant};

fn main() {
    let args: Vec<_> = env::args().collect();
    let n = args[1].parse().unwrap();

    let a = &matrix_new(n);
    let b = &matrix_new(n);

    let t1 = Instant::now();
    let mut c = (0..n).map(move |_| {
        (0..n).map(move |i| (0..n).map(|j| a[i * n + j] * b[j * n + i]).sum::<f64>())
    });

    let t2 = Instant::now();

    println!("  time = {:?}", t2.duration_since(t1));
    println!("     n = {}", n);
    println!("result = {}", c.nth(n / 2).unwrap().nth(n / 2).unwrap());
}

fn matrix_new(n: usize) -> Vec<f64> {
    let tmp = 1.0 / n as f64 / n as f64;
    (0..n)
        .flat_map(|i| (0..n).map(move |j| tmp * (i as isize - j as isize) as f64 * (i + j) as f64))
        .collect()
}

Вот типичное раст-говно. Во-первых мы сразу видим то, что раст-сектант отказывается от своего говна:

unwrap
unwrap
unwrap

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

let args: Vec<_> = env::args().collect();

Здесь опять же видно, что говно не может в вывод типов.

let a = &matrix_new(n);

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

let t1 = Instant::now();

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

map(move |_| {

Здесь же опять видно нелепость мусорного синтаксиса. Мусорный move, мусоорное ||, которое никак не соотносится с функцией, её типом и прочим.

(0..n).map(move |i| (0..n).map(|j| a[i * n + j] * b[j * n + i]).sum::<f64>())

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

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

.sum::<f64>()

Здесь же очередная бездарность. Во-первых отсутствия вывода типов. Во-вторых sum::<f64> вместо нормального sum<f64>()

println!(

Мусорное неосиляторство с мусорным ! и говномакросами.

t2.duration_since(t1)

Мусорные функции, неспособность этого говна в операторы. Это говно вместо t2 - t1

c.nth(n / 2).unwrap().nth(n / 2).unwrap()

Мусорное говно вместо c[n / 2][n / 2] - опять же сектант пытается эмулировать исключения + неспособность бездарностей в операторы.

fn matrix_new(n: usize) -> Vec<f64> {

Мусорное fn, мусорное -> Vec<f64> - неспособность бездарностей в вывод типов и парсер.

let tmp = 1.0 / n as f64 / n as f64;

Неспособность бездарностей в неявные касты. Говно вместо 1. / n / n

.flat_map(|i| (0..n).map(move |j| tmp * (i as isize - j as isize) as f64 * (i + j) as f64))

Всё тоже самое. Мусорное говно с ручными кастами. Неспособность в вывод типов.

anonymous
()
Ответ на: комментарий от eao197

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

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

И это без учёта того, что это говно в миллионы раз сливает С++ по производительности.

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

Следующий высер ещё хуже.

use std::{env, time::Instant};

fn main() {
    let args: Vec<_> = env::args().collect();
    let n = args[1].parse().unwrap();

    let tmp = 1.0 / n as f64 / n as f64;
    let a = (0..n)
        .map(|i| (0..n).map(move |j| tmp * (i as isize - j as isize) as f64 * (i + j) as f64));
    let b = (0..n)
        .map(|i| (0..n).map(move |j| tmp * (j as isize - i as isize) as f64 * (i + j) as f64));

    let t1 = Instant::now();
    let mut c = a.map(move |row| {
        b.clone().map(move |col| {
            let row = row.clone();
            move || col.zip(row).map(|(b, a)| a * b).sum::<f64>()
        })
    });
    let t2 = Instant::now();

    println!("  time = {:?}", t2.duration_since(t1));
    println!("     n = {}", n);
    println!("result = {}", c.nth(n / 2).unwrap().nth(n / 2).unwrap()());
}

Тут сектант 1в1 повторил все следствия из моих тезисов.

anonymous
()
Ответ на: комментарий от grem

Цель темы была не в написании своего велосипеда по матрицам, а в попытке понять, как писать на Rust, чтобы приблизиться по скорости выполнения к С. Выяснилось, что правильный путь – использование итераторов вместо [].

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

Собственно, что я и говорил. Опущенная мною шлюха декларирует «потрут» и так же пугает меня этим. Я валял эту мразь в дерьме тут, в соседней теме. Шлюхи бежит рыдать, стучать и затирать свой позор.

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

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

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

Звиняй, чувак. Время, чтобы длинные посты писать, тут похоже только у тебя есть. Да ещё и писать их в такой форме, чтобы их точно вытерли, а потом на это обижаться.

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

Моё мнение есть смысл сравнивать синтаксис когда языки предоставляют схожие возможности

А какая тут связь? Понятно, если б речь шла про языковые возможности: смотрите, тут паттерн-матчинг читаемее чем тут, а тут динамические типы, поэтому синтаксис проще. А JVM там или RC под капотом - вообще ортогонально.

anonymous
()
Ответ на: комментарий от RazrFalcon

Это вы про бесполезный return? Ну ок.

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

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

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

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

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

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

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

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

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

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

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

Касательно «проблем» нет. Эта шлюха уже накукарекалась на вечное валяние в дерьме. Показываю ту же риторику 1в1.

Обещанная риторика.

https://habr.com/ru/post/450512/#comment_20147432 - идём сюда, читаем:

Понял. Алгоритм мёржа неверный. А однопоточная версия в этом варианте будет медленнее из-за валидации utf-8, mmap'а и другого подхода к парсингу. Много переделывать надо. Может быть позже.

Это не читаем, данные потуги все были умножены мною на ноль - данная бездарность попросту несёт херню. Хотя это норма для подобного биомусора.

Нам интересует это:

К слову, то, насколько просто можно распараллелить програму, тоже играет свою роль.

Здесь эта мразь транслирует методичку вида «на говнорасте лучше», причём никаких измерений эта шлюха не ставила и сказать что-то может? Почему же она может? Почему ей это делать не запрещено?

Эту задачу нетривиально распараллелить линейно. Поэтому приходится тратить время на раскидывание миллиона объектов по нескольким потокам (оверхед около 300нс на объект, но накапливается), вместо того, чтобы разбить файл на несколько частей и отдать каждую своему потоку. Скажем есть у нас позиция в середине JSON, как вы определите в общем случае откуда начинается следующий объект? Придётся писать особый вариант парсинга со сканированием назад.

Далее тут видно, как эта шлюха опять пытается блеять. Несёт херню про какие-то «нетривиально»(запомним это), про какое-то раскидывание, про какие-то 300нс и прочую чушь.

Кстати, тут можно заметить ещё одно. Бездарное раст-отребье неспособно писать многопоток необосравшись. И никакой говнораст им не помог. Они не смогли написать рабочий мерж.

У вас всё в порядке? Обычное желание выжать максимум из кода.

Вот тут эта падаль заявляет свою мотивацию. Это нужно так же запомнить.

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

Ну и финалочка.

https://habr.com/ru/post/450512/#comment_20149214 - я показал результат, о котором говорит. Я доказал каждый свой тезис.

А теперь внимание. Что же кукарекала эта шлюха? На расте проще. Куда она пропала? Ой, сразу убежала? А где же нетривиально, а где же 200нс? А где раскидывание? Проще ведь.

А куда же шлюха пропала? Где же все потуги «я пытаюсь выжать максимум»? А чего так сразу убежала? Ой, не смоглось?

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

Данная шлюха декларирует «на расте проще», причём никаких измерений не демонстрирует и никак себя не удаляет. Почему же?

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

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

anonymous
()
Ответ на: комментарий от red75prim

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

anonymous
()
Ответ на: комментарий от RazrFalcon

Реализацию я пишу один раз.

Ок. Write-only. Тогда вопросов нет.

Так надо оптимизации вообще выключать или нет? Это же свойство компилятора. И что с чем сравниваем то, если отключаем?

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

Вот это уже полезный вывод.

Если можешь, ссылку на итоговый вариант в тему вынеси, а то затеряется в бурном обсуждении ;)

Вот это?

На мой взгляд, оно того не стоило.

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

Я бесстыдно скопировал код red75prim и заменил им свой, написанный в лоб. Так что, финальный вариант можно посмотреть ткнув по ссылке Rust в ОП.

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

Ну то есть опыт в какой-то степени полезный (любой опыт полезен), но выглядит «криповенько».

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

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

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

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

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

Выяснилось, что правильный путь – использование итераторов вместо [].

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

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

Далее же тебя поимела пропаганда. Ведь ты там используешься раст-логику говна только для получения указателей(никаких итераторов там нет). Т.е. оверхед и мусорность раст-логики размазывается по сотням тысяч арифметических операций.

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

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.