簡體   English   中英

inheritance真的不影響性能嗎?

[英]Does inheritance really not affect performance?

我在互聯網上( 此處此處)發現 inheritance 不會影響 class 的性能。 我對此感到好奇,因為我一直在為渲染引擎編寫一個矩陣模塊,這個模塊的速度對我來說非常重要。

在我寫完之后:

  • 底座:通用矩陣class
  • 從基礎派生:方形實現
  • 派生自派生:方陣的 3-dim 和 4-dim 實現

我決定測試它們並面臨實例化的性能問題

所以主要的問題是:

  1. 在我的情況下,這些性能問題的原因是什么?為什么它們通常會發生?
  2. 在這種情況下,我應該忘記 inheritance 嗎?

這就是這些類的一般外觀:

template <class t>
class Matrix
{
protected:
    union {
        struct
        {
            unsigned int w, h;
        };
        struct
        {
            unsigned int n, m;
        };
    };

    /** Changes flow of accessing `v` array members */
    bool transposed;

    /** Matrix values array */
    t* v;

public:
    ~Matrix() {
        delete[] v;
    };
    Matrix() : v{}, transposed(false) {};

    // Copy
    Matrix(const Matrix<t>& m) : w(m.w), h(m.h), transposed(m.transposed) {
        v = new t[m.w * m.h];
        for (unsigned i = 0; i < m.g_length(); i++)
           v[i] = m.g_v()[i];
    };

    // Constructor from array
    Matrix(unsigned _w, unsigned _h, t _v[], bool _transposed = false) : w(_w), h(_h), transposed(_transposed) {
       v = new t[_w * _h];
       for (unsigned i = 0; i < _w * _h; i++)
           v[i] = _v[i];
    };

    /** Gets matrix array */
    inline t* g_v() const { return v; }
    /** Gets matrix values array size */
    inline unsigned g_length() const { return w * h; }

    // Other constructors, operators, and methods.
}



template<class t>
class SquareMatrix : public Matrix<t> {
public:
    SquareMatrix() : Matrix<t>() {};
    SquareMatrix(const Matrix<t>& m) : Matrix<t>(m) {};

    SquareMatrix(unsigned _s, t _v[], bool _transpose) : Matrix<t>(_s, _s, _v, _transpose) {};
    // Others...
}

template<class t>
class Matrix4 : public SquareMatrix<t> {
public:
    Matrix4() : SquareMatrix<t>() {};
    Matrix4(const Matrix<t>& m) : SquareMatrix<t>(m) {}

    Matrix4(t _v[16], bool _transpose) : SquareMatrix<t>(4, _v, _transpose) {};
    // Others...
}


為了進行測試,我使用了這個

void test(std::ofstream& f, char delim, std::function<void(void)> callback) {
    auto t1 = std::chrono::high_resolution_clock::now();
    callback();
    auto t2 = std::chrono::high_resolution_clock::now();
    f << std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count() << delim;
    //std::cout << "test took " << std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count() << " microseconds\n";
}

性能問題

使用單個 class 初始化,沒有問題 - 每個 class 幾乎每次都在 5 微秒以下。 但后來我決定擴大初始化的數量,他們的幾個麻煩發生了

我運行每個測試 100 次,長度為 500 的 arrays

1. Class 用默認構造函數初始化

原始結果

我剛剛測試了 arrays 的初始化

結果是(以微秒為單位的平均時間):

  • 矩陣 25.19
  • SquareMatrix 40.37(損失 37.60%)
  • Matrix4 58.06(SquareMatrix 損失 30.47%)

在這里我們已經可以看到巨大的不同

這是代碼

int main(int argc, char** argv)
{
    std::ofstream f("test.csv");
    f << "Matrix\t" << "SquareMatrix\t" << "Matrix4\n";

    for (int k = 0; k < 100; k++) {
        test(f, '\t', []() {
            Matrix<long double>* a = new Matrix<long double>[500];
            });

        test(f, '\t', []() {
            SquareMatrix<long double>* a = new SquareMatrix<long double>[500];
            });

        test(f, '\n', []() {
            Matrix4<long double>* a = new Matrix4<long double>[500];
            });
    }

    f.close();

    return 0;
}

2. Class 用默認構造函數初始化和填充

原始結果

測試了 class 實例的 arrays 的初始化,然后用自定義矩陣填充它們

結果(以微秒為單位的平均時間):

  • 矩陣 402.8
  • SquareMatrix 475(15.20% 損失)
  • Matrix4 593.86(SquareMatrix 損失 20.01%)

代碼

int main(int argc, char** argv)
{
    long double arr[16] = {
       1, 2, 3, 4,
       5, 6, 7, 8,
       9, 10, 11, 12,
       13, 14,15,16
    };

    std::ofstream f("test.csv");
    f << "Matrix\t" << "SquareMatrix\t" << "Matrix4\n";

    for (int k = 0; k < 100; k++) {
        test(f, '\t', [&arr]() {
            Matrix<long double>* a = new Matrix<long double>[500];
            for (int i = 0; i < 500; i++) 
                a[i] = Matrix<long double>(4, 4, arr);
            });

        test(f, '\t', [&arr]() {
            SquareMatrix<long double>* a = new SquareMatrix<long double>[500];
            for (int i = 0; i < 500; i++) 
                a[i] = SquareMatrix<long double>(4, arr);
            });

        test(f, '\n', [&arr]() {
            Matrix4<long double>* a = new Matrix4<long double>[500];
            for (int i = 0; i < 500; i++) 
                a[i] = Matrix4<long double>(arr);
            });
    }

    f.close();

    return 0;
}

3. 用 class 實例填充向量

原始結果

將自定義矩陣推回向量

結果(以微秒為單位的平均時間):

  • 矩陣 4498.1
  • SquareMatrix 4693.93(損失 4.17%)
  • Matrix4 4960.12(其 SquareMatrix 損失 5.37%)

代碼

int main(int argc, char** argv)
{
    long double arr[16] = {
       1, 2, 3, 4,
       5, 6, 7, 8,
       9, 10, 11, 12,
       13, 14,15,16
    };

    std::ofstream f("test.csv");
    f << "Matrix\t" << "SquareMatrix\t" << "Matrix4\n";

    for (int k = 0; k < 100; k++) {
        test(f, '\t', [&arr]() {
            std::vector<Matrix<long double>> a = std::vector<Matrix<long double>>();
            for (int i = 0; i < 500; i++)
                a.push_back(Matrix<long double>(4, 4, arr));
            });

        test(f, '\t', [&arr]() {
            std::vector<SquareMatrix<long double>> a = std::vector<SquareMatrix<long double>>();
            for (int i = 0; i < 500; i++)
                a.push_back(SquareMatrix<long double>(4, arr));
            });

        test(f, '\n', [&arr]() {
            std::vector<Matrix4<long double>> a = std::vector<Matrix4<long double>>();
            for (int i = 0; i < 500; i++)
                a.push_back(Matrix4<long double>(arr));
            });
    }

    f.close();

    return 0;
}

如果你需要所有的源代碼,你可以在這里查看matrix.hmatrix.cpp

inheritance真的不影響性能嗎?

是的。 只要不涉及虛方法,Inheritance 就不會影響運行時性能。 (因為只有這樣你才需要在運行時推斷類型並調用相應的虛擬方法覆蓋)。 實際上,如果您深入了解細節,您就會知道 c++ inheritance 大多只是 static 的事情,即在編譯時完成。

在我的情況下,這些性能問題的原因是什么?為什么它們通常會發生?

啟用優化后,這些似乎效果很好?

在這種情況下,我應該忘記 inheritance 嗎?

在這種對性能敏感的情況下,您唯一需要做的就是避免使用虛擬方法。

與這個問題無關的東西。 我已經閱讀了你的代碼。 也許在 header 文件中實現您的模板會更好?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM