Почему замена элементов в [] float64 в Go быстрее, чем замена элементов в Vecв ржавчине? - PullRequest
0 голосов
/ 22 октября 2018

У меня есть две (эквивалентные?) Программы, одна в Go, другая в Rust.Среднее время выполнения:

  • Go ~ 169ms
  • Rust ~ 201ms

Go

package main

import (
    "fmt"
    "time"
)

func main() {
    work := []float64{0.00, 1.00}
    start := time.Now()

    for i := 0; i < 100000000; i++ {
        work[0], work[1] = work[1], work[0]
    }

    elapsed := time.Since(start)
    fmt.Println("Execution time: ", elapsed)
}

Rust

Я скомпилировал с --release

use std::time::Instant;

fn main() {
    let mut work: Vec<f64> = Vec::new();
    work.push(0.00);
    work.push(1.00);

    let now = Instant::now();

    for _x in 1..100000000 {
        work.swap(0, 1); 
    }

    let elapsed = now.elapsed();
    println!("Execution time: {:?}", elapsed);
}

Является ли Rust менее производительным, чем Go в этом случае?Может ли программа Rust быть написана идиоматически, чтобы она выполнялась быстрее?

Ответы [ 2 ]

0 голосов
/ 22 октября 2018

(не ответ), но чтобы дополнить то, что написал Лукас, вот что Go 1.11 генерирует для самого цикла:

    xorl    CX, CX
    movsd   8(AX), X0
    movsd   (AX), X1
    movsd   X0, (AX)
    movsd   X1, 8(AX)
    incq    CX
    cmpq    CX, $100000000
    jlt     68

(Предоставлено https://godbolt.org)

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

0 голосов
/ 22 октября 2018

Может ли программа Rust быть написана идиоматически, чтобы она выполнялась быстрее?

Да.Чтобы создать вектор с несколькими элементами, используйте макрос vec![]:

let mut work: Vec<f64> = vec![0.0, 1.0];    

for _x in 1..100000000 {
    work.swap(0, 1); 
}

Так этот код быстрее?Да.Посмотрите , какая сборка генерируется :

example::main:
  mov eax, 99999999
.LBB0_1:
  add eax, -11
  jne .LBB0_1
  ret

На моем ПК это работает примерно в 30 раз быстрее, чем ваш исходный код.

Почему сборка все еще содержит этот цикл, который ничего не делает?Почему компилятор не может увидеть, что два push совпадают с vec![0.0, 1.0]?Оба очень хорошие вопросы, и оба, вероятно, указывают на недостаток в LLVM или компиляторе Rust.

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

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

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