#rust
Вопрос:
У меня было много проблем с rust, когда производительность моих программ была бы совершенно непредсказуемой и резко менялась бы при незначительных изменениях. Возьмем, к примеру, этот код ржавчины:
use std::time::Instant;
#[derive(Clone, Copy, PartialEq, Eq)]
enum Foo {
A,
B,
C,
}
struct Bar {
arr: Vec<u32>,
}
impl Bar {
pub fn new() -> Self {
Self { arr: vec![0; 64] }
}
pub fn calc(amp;self, arr: amp;mut [Foo], pos: usize) -> (i32, i32) {
let mut a = 0;
let mut b = 0;
let x = amp;self.arr[pos];
for i in 0..10 {
if arr[(pos i) % 64] == Foo::A {
a = 1;
} else if arr[(pos i) % 64] == Foo::B {
b = 1;
}
}
(a, b)
}
}
fn main() {
let bar = Bar::new();
let mut state = vec![Foo::C; 64];
let t1 = Instant::now();
for _ in 0..1000000 {
for pos in 0..64 {
let x = bar.calc(amp;mut state, pos);
}
}
println!("{}", t1.elapsed().as_millis());
}
В последней стабильной версии rust с режимом выпуска это занимает ~245 мс на моем i7 7700hq.
Однако измените fn calc
объявление как таковое:
pub fn calc(amp;self, arr: amp;mut Vec<Foo>, pos: usize) -> (i32, i32)
Я получаю 1550 мс. Более того, по ночам исходная функция занимает столько же времени, сколько и вторая, всего 100 мс.
Измените что-то незначительное , например, закомментируйте строку let x = amp;self.arr[pos];
, измените перечисление на int, измените функцию, которую нужно выполнить amp;mut self
, и вы получите совершенно другой набор результатов, по-видимому, случайным образом.
Мне нравится rust, но я изо всех сил пытаюсь оправдать его использование по сравнению с c , когда я могу быть вынужден пытаться оптимизировать бессмысленными способами, когда он работает хуже в несколько раз в, казалось бы, случайных ситуациях. Эти тесты могут показаться синтетическими, но я извлек их из проблем, которые обнаружил в реальном коде. Исправьте этот пример, и я могу дать вам еще 10.
Комментарии:
1. Просто проверяю, так как вы явно не упомянули об этом, но используете
--release
ли вы его при выполнении теста? Если нет, то скорость не имеет значения, так как она не выполняла никаких оптимизаций.2. @Locke да, я использую —release
3. Когда я пытаюсь запустить любую версию в режиме выпуска, она полностью оптимизирует вызов
calc
, так как это не имеет никакого эффекта. В конце концов он выводит 0 секунд для обоих вариантов на моей машине.4. Если вы запустите
cargo clippy
, он уведомит вас о наиболее распространенных потенциальных недостатках производительности, таких какVec
прямая передача вместо среза. Передача ссылки на aVec
приведет к созданию двойного указателя, который требует дополнительного разыменования при каждом доступе. С другой стороны, срез-это жирный указатель, так что у вас нет этой проблемы.5. Какую версию Rust вы используете? (
rustc --version
) Возможно, вы используете старую версию, которая плохо оптимизирует ваш код.