Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Производительность циклов и итераторов

Чтобы определить, использовать циклы или итераторы, нужно знать, какая реализация быстрее: версия функции search с явным циклом for или версия с итераторами.

Мы запустили бенчмарк, загрузив все содержимое The Adventures of Sherlock Holmes сэра Артура Конан Дойла в String и выполнив поиск слова the в содержимом. Вот результаты бенчмарка для версии search, использующей цикл for, и версии, использующей итераторы:

test bench_search_for  ... bench:  19,620,300 ns/iter (+/- 915,700)
test bench_search_iter ... bench:  19,234,900 ns/iter (+/- 657,200)

У двух реализаций похожая производительность! Мы не будем объяснять код бенчмарка здесь, потому что цель не в том, чтобы доказать эквивалентность двух версий, а в том, чтобы получить общее представление о том, как эти две реализации сравниваются по производительности.

Для более всестороннего бенчмарка стоит проверить разные тексты разного размера в качестве contents, разные слова и слова разной длины в качестве query, а также всевозможные другие варианты. Суть вот в чем: итераторы, хотя и являются высокоуровневой абстракцией, компилируются примерно в тот же код, как если бы вы сами написали низкоуровневый код. Итераторы – одна из абстракций с нулевой стоимостью Rust: мы имеем в виду, что использование абстракции не добавляет накладных расходов во время выполнения. Это похоже на то, как Бьерн Страуструп, первоначальный проектировщик и реализатор C++, определяет нулевые накладные расходы в своем докладе “Foundations of C++” на ETAPS в 2012 году:

В целом реализации C++ следуют принципу нулевых накладных расходов: за то, чем вы не пользуетесь, вы не платите. И далее: то, чем вы пользуетесь, вы не смогли бы написать вручную лучше.

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

Итоги

Замыкания и итераторы – возможности Rust, вдохновленные идеями языков функционального программирования. Они помогают Rust ясно выражать высокоуровневые идеи с низкоуровневой производительностью. Реализации замыканий и итераторов устроены так, что производительность во время выполнения не страдает. Это часть цели Rust – стремиться предоставлять абстракции с нулевой стоимостью.

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