Быстрый getter или странный бэнч


#1

Товарищи, объясните мне пожалуйста такую вот штуку

Стелал я бэнчмарки и получил для себя очень странный результат
https://play.rust-lang.org/?version=nightly&mode=release&edition=2018&gist=f6ef21667f99a0372d0d20a4096e1da5

Кто ответит на вопрос?
Почему чтение поля структуры медленнее чем чтение длины вектора структуры?

ПС: если надо инлайнить то как? у меня не молучилось


#2

Как только запостил так сразу и понял в чем беда))


#3

Кстати, о птичках: в реализации структуры (impl) можно использовать алиас Self не только в позиции возвращаемого значения метода, но и в его теле:

impl MyVec {
    fn new(...) -> Self {
        Self {...}
    }
}

#4

Было бы хорошо дать ответ :slight_smile:
Я например раст и более низкоуровневые вещи чем ruby плохо знаю и не только я :slight_smile:
Спасибо :slight_smile:


#5

Судя по смайлам, всё дело в невнимательности: результат первого теста выдается с размерностью наносекунд, а второго — миллисекунд. Если этого не заметить…


#6

Спасибо за вашу “помощь”, сам разобрался


#7

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


#8

@Virtuos86 @Stanislav-Lapata

Уважаемый @Virtuos86 не прав, дело совсем не в размерности (как раз таки по размерности видно потрясающую разницу в производительности). Посмотрите на этот пример: https://play.rust-lang.org/?version=nightly&mode=release&edition=2018&gist=81e7d1bdf5f4d20af1b71590475e2ac3

Подсказка - with_capacity не устанавливает длину вектора.


#9

Большое спасибо за наводку. Я действительно не обратил внимание на это обстоятельство.
Но, как справедливо заметили выше, было бы неплохо объяснить в чём тут собака зарыта.
Зайду издалека. Поскольку Rust хоть и высокоуровневый язык, но всё же язык системного программирования, даже не опускаясь, благодаря его высокоуровневым абстракциям, до ручного выделения памяти, мы можем в некоторых случаях гибко выбирать, сколько памяти выделять при создании экземпляров структур данных, если эти типы данных контейнеры, хранящие в себе другие данные.
Как можно вкратце ознакомиться в той части стандартной документации, которая посвящена такой структуре данных, как вектор Vec, вектор имеет две таких смежных характеристики, как длина length и емкость capacity.
Первая указывает, сколько элементов выбранного типа хранится в векторе на текущий момент, вторая показывает, сколько элементов в нем вообще может храниться без переаллокации. Емкость равняется произведению размера типа элементов, которые в нем хранятся, на Н-ое их количество и определяет количество памяти, которое выделено вектору для хранения данных. Что дает емкость? Она позволяет избавиться от переаллокаций. Если длина вектора превысит его емкость, соответственно вектор не сможет разместить элементы в выделенном ему пространстве и запросит другой, более емкий кусок памяти, в котором по новой переразместятся его данные. Это и называется переаллокацией, когда уже существующие данные меняют свою прописку. Процесс этот, разумеется, небыстрый, и его желательно избегать. Как это можно сделать? Заранее определить, какая емкость потребуется вектору и выделить память под нее единоразово. Эту возможность и дает метод-конструктор Vec::with_capacity. Что важно понимать, так это то, что в этом случае создается вектор указанной емкости, но нулевой длины.
Почему же бенчмарк ввел в заблуждение?
Обратим внимание на первый цикл:

for _ in 0..iters {
        ...
        for i in 0..v.len() {

v.len() раскрывается в v.inner.len(). Поскольку вектор изначально пустой (см. выше), то внутренний цикл будет выполняться 0 раз.
Во втором же примере

for _ in 0..iters {
    ...
    for i in 0..v.other_len() {

v.other_len() раскрывается в v.len, и внутренний цикл будет постоянно “бегать” от 0 до 1000, таким образом бенчмарк измеряет неидентичные с алгоритмической точки зрения куски кода и, следовательно, дает неверный результат.

cast @Stanislav-Lapata
// Даже здесь умудрился напутать с выводами, но исправился.


#10

да все верно. в итоге в одном случае замерял время по вектору с длиной 0