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 или версия с итераторами.

Мы провели замер (benchmark): загрузили в 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 и всякие другие варианты. Главное вот что: итераторы, хоть и являются высокоуровневой абстракцией, компилируются примерно в тот же код, какой вы написали бы сами на низком уровне. Итераторы — одна из абстракций с нулевой стоимостью (zero-cost abstractions) в Rust: их использование не добавляет накладных расходов во время выполнения. Это похоже на то, как Бьёрн Страуструп, создатель и первый разработчик C++, определяет принцип нулевых накладных расходов в своём докладе 2012 года на ETAPS «Foundations of C++»:

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

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

Итоги

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

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