2012-05-23 13 views
17

Czytałem kilka opisów dotyczących semantyki ruchu w C++ 11 i zastanawiam się, w jakim kontekście można z niej korzystać. Obecnie wiele bibliotek matematycznych C++ korzysta z metaprogramowania szablonu w celu opóźnienia oceny.Zrozumienie zalet semantyki ruchu w porównaniu do metaprogramowania szablonu

Jeśli M = A + B + C * D, gdzie M, A, B, C i D są macierzami, metaprogramowanie szablonów pozwala uniknąć niepotrzebnych kopii. Czy semantyka ruchu jest wygodniejszym sposobem robienia takich rzeczy?

Jeśli nie, w jakim kontekście używa się semantyki ruchu. Jeśli tak, jakie są różnice/ograniczenia w stosunku do metaprogramowania szablonu dla tego rodzaju użytkowania?

+4

Metaprogramowanie jest przeciwieństwem opóźniania oceny. Ciekawe pytanie, ale próbka twoich myśli byłaby pomocna. –

+0

Myślę, że różnica między tymi dwoma podejściami nie byłaby duża, ale myślę, że odniesienia do rvalue sprawiłyby, że biblioteka była nieco łatwiejsza i czystsza.

+3

@MooingDuck: szablony wyrażeń czasami umożliwiają coś więcej niż tylko usuwanie kopii. Na przykład w wyrażeniu 'A * B + C', szablon ekspresji może zoptymalizować obliczenia przez wstawienie instrukcji FMA, itp. –

Odpowiedz

13

Nie jestem ekspertem od tych optymalizacji, ale jak rozumiem, opóźnione techniki oceny, o których mówisz, działają poprzez zdefiniowanie operatorów arytmetycznych na twoim typie macierzy, tak że na przykład A+B+C*D nie zwraca macierzy, to zwraca obiekt proxy, który może przekształcić w macierz. Dzieje się tak, gdy jest przypisane do M, a kod konwersji obliczy każdą komórkę macierzy wyników za pomocą najbardziej efektywnych metod, jakie mogą stworzyć projektanci bibliotek, unikając tymczasowych obiektów macierzy.

Więc załóżmy, że program zawiera M = A + B + C * D;

Jeśli tak nic mądrego wdrażania operator+ inne niż w zwykły sposób z użyciem operator+=, można dostać coś takiego kiedyś normalne, C++ 03-styl kopia elizja ma kopnął w:

Matrix tmp1 = C; 
tmp1 *= D; 
Matrix tmp2 = A; 
tmp2 += B; 
tmp2 += tmp1; 
M = tmp2; 

z oceną opóźnieniem, można uzyskać coś więcej takich jak:

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; 
    } 
} 

natomiast "nic sprytny" kod wykonałby kilka oddzielnych dodatków i dużo więcej zadań.

O ile mi wiadomo, przenoszenie semantyki nie pomaga w tym przypadku. Nic w tym, co napisałeś pozwala nam przenieść się z A, B, C lub D, więc mamy zamiar skończyć z równowartości:

Matrix tmp1 = C; 
tmp1 *= D; 
Matrix tmp2 = A; 
tmp2 += B; 
tmp2 += std::move(tmp1); 
M = std::move(tmp2); 

więc przenieść semantykę nie pomógł z niczego innego niż ostatni bit, gdzie być może wersje rvalue operatorów są lepsze niż te regularne. Jest więcej dostępnych, jeśli napisałeś std::move(A) + std::move(B) + std::move(C) * std::move(D), ponieważ nie musielibyśmy kopiować z C lub A, ale nadal nie sądzę, że wynik jest tak dobry jak kod opóźnionej oceny.

Zasadniczo przenieść semantyka nie pomagają z niektórych ważnych elementów optymalizacji świadczonych przez opóźnione oceny:

1) z oceny opóźniony, wyniki pośrednie nie trzeba faktycznie istnieć jako kompletne matryc. Przenieś semantykę nie zapisuj kompilatora od utworzenia pełnej macierzy A+B w pamięci w pewnym momencie.

2) z opóźnioną oceną, możemy rozpocząć modyfikowanie M, zanim skończymy obliczanie całego wyrażenia. Przenoszenie semantyki nie ułatwia kompilatorowi zmiany kolejności modyfikacji: nawet jeśli kompilator jest wystarczająco inteligentny, aby wykryć potencjalną możliwość, modyfikacje w nie-tymczasowych plikach muszą być przechowywane w prawidłowej kolejności, jeśli istnieje jakiekolwiek zagrożenie wyjątku, ponieważ jeśli jakakolwiek część A + B + C * D rzuca, to M musi pozostać jak przy rozpoczęciu.

2

To dwie różne bestie. Przenieś semantykę dotyczy przywłaszczania zasobów z wartości, która ma zostać zniszczona. Po zmieszaniu z szablonami ekspresyjnymi np. Dużych int (które wymagają dynamicznej alokacji pamięci), wystarczy po prostu zastosować taką pamięć zamiast tworzyć kopię czegoś, co ma zostać zniszczone.

Move semantyka są również ważne dla obiektów, które nie są z natury copyable (jak fstreams), ale ma sens, aby ruchomą.

0

Przenoszenie semantyki dotyczy zasobów zarządzanych w obrębie obiektów i jest używane do unikania gromadzenia/zwalniania zasobów niepotrzebnie podczas tworzenia obiektów tymczasowych (e.e. dynamicznie alokowana pamięć jest zasobem).

Metaprogramowanie szablonu działa na strukturach, które są przydzielane na stosie (ponieważ wymagają one analizy czasu kompilacji operandów). Można go użyć do uniknięcia obliczeń w czasie wykonywania dla operacji, które można obliczyć w czasie kompilacji.

34

Uważam, że bardziej precyzyjnym określeniem tego, co nazywasz "metaprogramowaniem szablonu" jest expression templates.

Jeśli matryce przeznaczyć swoje dane dynamicznie przesunąć semantyka może pomóc przenieść te dane od obiektu do obiektu (w tym do/z tymczasowych) generowane podczas określenia takie jak:

M = A + B + C*D 

szablonów wypowiedzi, na z drugiej strony, całkowicie wyeliminuje tymczasowe.

Jeśli twoje macierze nie przypisują danych w sposób dynamiczny (np. Jeśli mają stały rozmiar i są małe), semantyka nie poprawi w żaden sposób Twojej wydajności.

Zastosowanie szablonów wyrażeń do biblioteki macierzy spowoduje najwyższą wydajność. Jest to również bardzo trudna technika implementacji. Przenoszenie semantyki jest łatwiejsze do implementacji i można je wykonać w uzupełnieniu do szablonów wyrażeń (jeśli istnieją zasoby, takie jak pamięć, którą można przenosić).

Podsumowując:

Move semantyka nie eliminuje temporaries, ale przeniesie dynamicznie przydzieloną pamięć wśród tymczasowych zamiast realokacji go.

Szablony wyrażeń eliminują tymczasowe.

0

Przenoszenie semantyki jest dynamiczne, szablony wyrażeń nie są. Nie można wyrenderować szablonu wyrażenia rozłożonego na kilka zdań, a część z nich jest oceniana tylko wtedy, gdy księżyc jest niebieski, podczas gdy semantyka ruchu może.

Powiązane problemy