Ich bin kein Experte für diese Optimierungen, aber wie ich es verstehe, funktionieren die verzögerten Auswertungstechniken, indem Sie arithmetische Operatoren auf Ihrem Matrix-Typ definieren, so dass zum Beispiel A+B+C*D
keine Matrix zurückgibt gibt ein Proxy-Objekt zurück, das in eine Matrix konvertieren kann. Dies passiert, wenn es M
zugeordnet ist, und der Umwandlungscode berechnet jede Zelle der Ergebnismatrix mit den effizientesten Mitteln, die die Bibliotheksdesigner erstellen können, um temporäre Matrixobjekte zu vermeiden.
So nehme an, das Programm enthält M = A + B + C * D;
Wenn Sie nichts tat klug andere als operator+
auf die übliche Art und Weise zu implementieren operator+=
verwenden, würden Sie so etwas wie dies einmal normal, C++ 03-Stil Kopie elision erhalten hat trat in:
Matrix tmp1 = C;
tmp1 *= D;
Matrix tmp2 = A;
tmp2 += B;
tmp2 += tmp1;
M = tmp2;
mit der verzögerten Auswertung, könnte man etwas mehr wie bekommen:
for (int i = 0; i < M.rows; ++i) {
for (int j = 0; j < M.cols; ++j) {
/* not necessarily the best matrix multiplication, but serves to illustrate */
c_times_d = 0;
for (int k = 0; k < C.cols; ++k) {
c_times_d += C[i][k] * D[k][j];
}
M[i][j] = A[i][j] + B[i][j] + c_times_d;
}
}
, während der "nichts clevere" Code einige separate Additionsschleifen und viel mehr Zuweisung machen würde.
Soweit mir bekannt ist, hilft Umzug Semantik in diesem Fall nicht viel. Nichts in dem, was Sie geschrieben haben, ermöglicht es uns, von A
, B
, C
oder D
zu bewegen, so werden wir mit dem Äquivalent von am Ende:
Matrix tmp1 = C;
tmp1 *= D;
Matrix tmp2 = A;
tmp2 += B;
tmp2 += std::move(tmp1);
M = std::move(tmp2);
So Semantik bewegen nicht mit etwas anderem geholfen als das letzte Bit, wo vielleicht die Rvalue-Versionen der Operatoren besser sind als die regulären. Es gibt mehr verfügbar, wenn Sie std::move(A) + std::move(B) + std::move(C) * std::move(D)
geschrieben haben, weil wir nicht von C
oder A
kopieren müssten, aber ich denke immer noch nicht, dass das Ergebnis so gut wie der verzögerte Evaluierungscode ist.
Grundsätzlich bewegt Semantik durch verzögerte Auswertung zur Verfügung gestellt nicht mit einigen wichtigen Teilen der Optimierung helfen:
1) mit verzögerter Auswertung, die Zwischenergebnisse müssen eigentlich nie als vollständige Matrizen existieren. Die Verschiebungssemantik speichert den Compiler nicht davor, die vollständige Matrix A+B
irgendwann im Speicher zu erstellen.
2) mit verzögerter Auswertung können wir anfangen, M
zu ändern, bevor wir die Berechnung des gesamten Ausdrucks abgeschlossen haben. Die Move-Semantik hilft dem Compiler nicht, Änderungen neu zu ordnen: Selbst wenn der Compiler schlau genug ist, um die potenzielle Gelegenheit zu erkennen, müssen Änderungen an Nicht-Provisorien in der richtigen Reihenfolge gehalten werden, wenn die Gefahr besteht, dass eine Ausnahme ausgelöst wird Wenn irgendein Teil von A + B + C * D
wirft, dann muss M
verlassen werden, wie es begann.
Metaprogrammierung ist das genaue Gegenteil der verzögernden Auswertung. Eine interessante Frage, aber eine Probe Ihrer Gedanken wäre hilfreich. –
@MooingDuck: Ausdruck Vorlagen ermöglichen manchmal mehr als nur die Beseitigung von Kopien. Zum Beispiel in einem 'A * B + C'-Ausdruck könnte die Ausdruckschablone die Berechnung durch Einfügen von FMA-Anweisungen usw. optimieren. –