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.
Metaprogramowanie jest przeciwieństwem opóźniania oceny. Ciekawe pytanie, ale próbka twoich myśli byłaby pomocna. –
@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. –