2012-05-23 5 views
17

Ich habe einige Beschreibungen über Verschieben Semantik in C++ 11 gelesen und ich frage mich, in welchem ​​Kontext es verwendet werden könnte. Derzeit verwenden viele mathematische C++ - Bibliotheken die Template-Metaprogrammierung, um die Auswertung zu verzögern.Verstehen der Vorteile von Bewegungssemantik vs Vorlage Metaprogrammierung

Wenn M = A + B + C * D ist, wobei M, A, B, C und D Matrix sind, können durch Template-Metaprogrammierung unnötige Kopien vermieden werden. Ist Umzug Semantik eine bequemere Art, diese Art von Dingen zu tun?

Wenn nicht, in welchem ​​Kontext moves Semantics verwendet wird. Wenn ja, was sind die Unterschiede/Einschränkungen im Vergleich zur Template-Metaprogrammierung für diese Art der Verwendung?

+4

Metaprogrammierung ist das genaue Gegenteil der verzögernden Auswertung. Eine interessante Frage, aber eine Probe Ihrer Gedanken wäre hilfreich. –

+0

Ich denke, der Unterschied zwischen den beiden Ansätze wäre nicht groß, aber ich denke, Rvalue Referenzen würde die Bibliothek etwas einfacher und sauberer machen.

+3

@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. –

Antwort

13

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.

2

Sie sind zwei verschiedene Tiere. Move Semantics bedeutet, sich Ressourcen aus einem Wert zu beschaffen, der zerstört werden soll. Wenn man sie mit Ausdrucksvorlagen von beispielsweise Big Ints (die eine dynamische Speicherzuweisung benötigen) vermischt, würde man sich einfach solchen Speicher aneignen, anstatt eine Kopie von etwas zu machen, das gerade zerstört werden soll.

Verschieben Semantik ist auch wichtig für Objekte, die von Natur aus nicht kopierbar (wie fstreams) sind aber sinnvoll bewegliche zu machen.

0

Die Verschiebungssemantik ist auf Ressourcen anwendbar, die in Objekten verwaltet werden, und wird verwendet, um das unnötige Erwerben/Freigeben von Ressourcen zu vermeiden, wenn temporäre Objekte erzeugt werden (z. B. ein dynamisch zugeordneter Speicher ist eine Ressource).

Template Metaprogrammierung funktioniert auf Strukturen, die auf dem Stack zugeordnet sind (da es eine Kompilierzeitauswertung der Operanden benötigt). Sie könnten es verwenden, um Laufzeitberechnung für Operationen zu vermeiden, die zur Kompilierungszeit berechnet werden können

34

Ich glaube, ein genauer Begriff für das, was Sie "Template Metaprogramming" nennen, ist expression templates.

Wenn Ihre Matrizen ihre Daten dynamisch zuordnen, kann zum Objekt Semantik bewegen helfen, dass die Daten aus dem Objekt zu übertragen (einschließlich zu/von den Provisorien) während eines Ausdrucks erzeugt wie:

M = A + B + C*D 

Expression Vorlagen, auf dem Andererseits werden die Provisorien vollständig eliminiert.

Wenn Ihre Matrizen ihre Daten nicht dynamisch zuweisen (z. B. wenn sie fest und klein sind), wird die Bewegungssemantik Ihre Leistung überhaupt nicht unterstützen.

Die Verwendung von Expressionsvorlagen in einer Matrixbibliothek führt zu der höchsten Leistung. Es ist auch eine sehr schwierige Implementierungstechnik. Verschieben Sie Semantik ist viel einfacher zu implementieren, und kann zusätzlich zu Ausdruck Vorlagen (wenn Ressourcen wie Speicher, die übertragen werden können) durchgeführt werden.

Zusammengefasst:

Verschieben Semantik nicht beseitigt Provisorien, wird aber unter den Provisorien statt Neuzuteilung es dynamisch zugewiesenen Speicher übertragen.

Expression-Vorlagen beseitigen die Provisorien.

0

Move-Semantik ist dynamisch, Expression-Templates sind nicht. Sie können nicht Ausdruck Vorlage einen Ausdruck, der über mehrere Aussagen verteilt ist und ein Teil davon wird nur ausgewertet, wenn der Mond blau ist, während Move Semantik kann.