- ヒープの割り当ては確かに非常に高価です。
- 時期尚早の最適化は悪いですが、ライブラリが非常に一般的で行列が巨大な場合、効率的な設計を探すのは時期尚早ではないかもしれません。結局のところ、多くの依存関係を蓄積した後でデザインを変更したくはありません。
- この問題に取り組むことができるさまざまなレベルがあります。たとえば、メモリアロケータレベル(スレッドごとのメモリプールなど)でヒープ割り当ての費用を回避できます。
- ヒープの割り当てにはコストがかかりますが、1つの巨大なマトリックスを作成するのは、マトリックスに対してかなり高価な操作(通常は線形の複雑さ以下)を実行するためだけです。相対的に言えば、フリーストアにマトリックスを割り当てることは、後で必然的に行う必要があるものと比較してそれほど高価ではない可能性があります。したがって、並べ替えなどの関数の全体的なロジックと比較すると、実際にはかなり安価である可能性があります。
将来の可能性として#3を考慮して、自然にコードを書くことをお勧めします。つまり、一時的なものの作成を加速するために、中間計算のために行列バッファーへの参照を取り入れないでください。一時的なものを作成し、値で返します。正確さと優れた明確なインターフェースが最初に来ます。
ここでの主な目標は、マトリックスの作成ポリシーを(アロケータまたはその他の手段を介して)分離することです。これにより、既存のコードをあまり変更せずに、後付けとして最適化する余地が生まれます。関連する関数の実装の詳細のみを変更するか、さらに良いことに、マトリックスクラスの実装のみを変更することでそれを実行できる場合は、設計を変更せずに自由に最適化できるため、非常にうまくいきます。それを可能にする設計は、一般的に効率の観点から完全になります。
警告:以下は、すべてのサイクルを最大限に活用したい場合にのみ使用することを目的としています。#4を理解し、優れたプロファイラーを身に付けることが不可欠です。また、ヒープ割り当てを最適化しようとするよりも、これらのマトリックスアルゴリズムのメモリアクセスパターンを最適化する方がうまくいく可能性があることにも注意してください。
メモリ割り当てを最適化する必要がある場合は、スレッドごとのメモリプールなどの一般的なもので最適化することを検討してください。たとえば、マトリックスにオプションのアロケータを取り入れることもできますが、ここではオプションを強調し、最初に簡単なアロケータの実装で正確さを強調します。
言い換えると:
各関数内でM1(n、p)を宣言するか、main()で一度だけ宣言し、各関数がスクラップスペースとして使用できる一種のバケットとして各関数に渡す方がよいでしょう。
先に進み、各関数で一時としてM1を作成します。中間結果を計算するためだけにクライアントに意味のないマトリックスを作成するようにクライアントに要求することは避けてください。これは、インターフェースを設計するときに実行しないように努めるべき最適化の詳細を公開することになります(クライアントが知る必要のないすべての詳細を非表示にします)。
代わりに、オプションのアロケータのように、これらの一時的なものの作成を加速するオプションが絶対に必要な場合は、より一般的な概念に焦点を合わせてください。これは、次のような実用的な設計に適合しますstd::set
。
std::set<int, std::less<int>, MyFastAllocator<int>> s; // <-- okay
ほとんどの人はそうしますが:
std::set<int> s;
あなたの場合、それは単に次のようになります:M1 my_matrix(n、p、alloc);
微妙な違いですが、アロケータはキャッシュされた行列よりもはるかに一般的な概念であり、関数が結果をより高速に計算するために必要なキャッシュの一種であることを除けば、クライアントにとって意味がありません。一般的なアロケータである必要はないことに注意してください。これは、マトリックスコンストラクターに渡される、事前に割り当てられたマトリックスバッファーである可能性がありますが、概念的には、クライアントにとって少し不透明なものであるという事実のために、それを分離することをお勧めします。
さらに、この一時マトリックスオブジェクトを作成するには、スレッド間で共有しないように注意する必要があります。これは、最適化ルートを実行する場合に概念を少し一般化する必要があるもう1つの理由です。マトリックスアロケータのようなもう少し一般的なものは、スレッドセーフを考慮に入れるか、少なくとも、別のアロケータがすべきことを設計によってさらに強調することができるからです。スレッドごとに作成されますが、生のマトリックスオブジェクトはおそらく作成できません。
上記は、インターフェースの品質を何よりも重視する場合にのみ役立ちます。そうでない場合は、アロケータを作成するよりもはるかに簡単なので、Matthieuのアドバイスに従うことをお勧めしますが、どちらも高速バージョンをオプションにすることを強調しています。