Почему в документации Rust говорится, что цикл while над массивом медленнее цикла for? - PullRequest
0 голосов
/ 28 мая 2019

Когда я читал документацию по ржавчине, я наткнулся на этот код , который итерирует массив a, используя цикл while (с индексом):

fn main() {
    let a = [10, 20, 30, 40, 50];
    let mut index = 0;

    while index < 5 {
        println!("the value is: {}", a[index]);

        index += 1;
    }
}

Документацияговорит:

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

Первая причина не требует пояснений.Вторая причина была в том, что я запутался.

Кроме того, они предложили использовать для этого цикл for.

fn main() {
    let a = [10, 20, 30, 40, 50];

    for element in a.iter() {
        println!("the value is: {}", element);
    }
}

Я просто не могу обернуться вокруг этого.Есть ли какое-то поведение, которое делает компилятор Rust?

1 Ответ

2 голосов
/ 28 мая 2019

Две части дополняют друг друга:

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

Каждый раз, когда вы пишете some_slice[some_index], стандартная библиотека делает эквивалент:

if some_index < some_slice.len() {
    some_slice.get_the_value_without_checks(some_index)
} else {
    panic!("Hey, stop that");
}

компилятор добавляет код времени выполнения для выполнения условной проверки каждого элемента

В цикле это выглядит примерно так:

while some_index < limit {
    if some_index < some_slice.len() {
        some_slice.get_the_value_without_checks(some_index)
    } else {
        panic!("Hey, stop that");
    }
    some_index += 1;
}

Эти повторяющиеся условия - не самый эффективный код.

Реализации Iterator для слайсов используют код unsafe, чтобы повысить его эффективность за счет более сложного кода. Итераторы содержат необработанные указатели на данные, но гарантируют, что вы никогда не сможете использовать их неправильно, чтобы вызвать небезопасную память. Без необходимости выполнять это условие на каждом шаге решение итератора будет часто быстрее 1 . Это более или менее эквивалентно:

while some_index < limit {
    some_slice.get_the_value_without_checks(some_index)
    some_index += 1;
}

Смотри также:


1 - как Матье М. указывает :

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

Смотри также:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...