Код на Python более эффективен, чем eigen3 или обычный C ++ - PullRequest
3 голосов
/ 10 июля 2019

У меня был некоторый код на Python3 (с numpy), который я хотел преобразовать в C ++ (с eigen3), чтобы получить более эффективную программу. Поэтому я решил протестировать простой пример, чтобы оценить прирост производительности, который я получу. Код состоит из двух случайных массивов, которые необходимо умножить на коэффициент. Мои выводы заключались в том, что код на python с numpy примерно на 30% быстрее, чем в C ++. Я хотел бы знать, почему интерпретируемый код Python быстрее, чем скомпилированный код C ++. Я что-то упустил в коде C ++?

Я использую gcc 9.1.0, Eigen 3.3.7, Python 3.7.3 и Numpy 1.16.4.

Возможные объяснения:

Программа на C ++ не использует векторизацию
Numpy намного более оптимизирован, чем я думал
Время измеряет разные вещи в каждой программе

Существует аналогичный вопрос в Переполнении стека ( Сравнение Eigen Matrix и Numpy Array ). Я проверил это на своем компьютере и получил ожидаемый результат, что eigen более эффективен, чем numpy, но здесь используется матричное умножение, а не умножение на коэффициент.

Код Python (main.py)
Команда выполнения: python3 main.py

import numpy as np
import time

Lx = 4096
Ly = 4000

# Filling arrays
a = np.random.rand(Lx, Ly).astype(np.float64)
a1 = np.random.rand(Lx, Ly).astype(np.float64)

# Coefficient-wise product
start = time.time()
b = a*a1

# Compute the elapsed time
end = time.time()

print(b.sum())
print("duration: ", end-start)

код C ++ с eigen3 (main_eigen.cpp)
Команда компиляции: g ++ -O3 -I / usr / include / eigen3 / main_eigen.cpp -o prog_eigen

#include <iostream>
#include <chrono>
#include "Eigen/Dense"

#define Lx 4096
#define Ly 4000
typedef double T;

int main(){

    // Allocating arrays
    Eigen::Array<T, -1, -1> KPM_ghosts(Lx, Ly), KPM_ghosts1(Lx, Ly), b(Lx,Ly);

    // Filling the arrays
    KPM_ghosts.setRandom();
    KPM_ghosts1.setRandom();

    // Coefficient-wise product
    auto start = std::chrono::system_clock::now();
    b = KPM_ghosts*KPM_ghosts1;

    // Compute the elapsed time
    auto end = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed_seconds = end-start;
    std::cout << "elapsed time: " << elapsed_seconds.count() << "s\n";

    // Print the sum so the compiler doesn't optimize the code away
    std::cout << b.sum() << "\n";

    return 0;
}

Простой код C ++ (main.cpp)
Команда компиляции: g ++ -O3 main.cpp -o prog

#include <iostream>
#include <chrono>

#define Lx 4096
#define Ly 4000
#define N Lx*Ly
typedef double T;

int main(){
    // Allocating arrays
    T lin_vector1[N];
    T lin_vector2[N];
    T lin_vector3[N];

    // Filling the arrays
    for(unsigned i = 0; i < N; i++){
        lin_vector1[i] = std::rand()*1.0/RAND_MAX;
        lin_vector2[i] = std::rand()*1.0/RAND_MAX;
    }

    // Coefficient-wise product
    auto start = std::chrono::system_clock::now();
    for(unsigned i = 0; i < N; i++)
        lin_vector3[i] = lin_vector1[i]*lin_vector2[i];

    // Compute the elapsed time
    auto end = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed_seconds = end-start;
    std::cout << "elapsed time: " << elapsed_seconds.count() << "s\n";

    // Print the sum so the compiler doesn't optimize the code away
    double sum = 0;
    for(unsigned i = 0; i < N; i++)
        sum += lin_vector3[i];
    std::cout << "sum: " << sum << "\n";


    return 0;
}

Время выполнения каждой программы 10 раз

Обычный C ++
прошедшее время: 0,210664 с
прошедшее время: 0,215406 с
прошедшее время: 0,222483 с
прошедшее время: 0,21526 с
прошедшее время: 0,216346 с
истекшее время: 0,218951 с
прошедшее время: 0,21587 с
прошедшее время: 0,213639 с
прошедшее время: 0,219399 с
прошедшее время: 0,213403 с

Обычный C ++ с собственным 3
прошедшее время: 0,21052 с
прошедшее время: 0,220779 с
прошедшее время: 0,216269 с
прошедшее время: 0,229234 с
прошедшее время: 0,212265 с
прошедшее время: 0,256714 с
прошедшее время: 0,212396 с
прошедшее время: 0,248241 с
прошедшее время: 0,241537 с
прошедшее время: 0,323519 с

Python
длительность: 0,23946428298950195
продолжительность: 0.1663036346435547
продолжительность: 0,17225909233093262
продолжительность: 0,15922021865844727
продолжительность: 0.16628384590148926
продолжительность: 0.15654635429382324
продолжительность: 0.15859222412109375
продолжительность: 0,1633443832397461
продолжительность: 0.1685199737548828
продолжительность: 0.16393446922302246

...