Koszt przejazdu przez wspólny PST
Używam STD::tr1:: shared_ptr intensywnie w całej mojej aplikacji. Obejmuje to przekazywanie obiektów jako argumentów funkcji. Rozważmy następujące:
class Dataset {...}
void f( shared_ptr< Dataset const > pds ) {...}
void g( shared_ptr< Dataset const > pds ) {...}
...
Podczas gdy przekazywanie obiektu zbioru danych przez shared_ptr gwarantuje jego istnienie wewnątrz f I g, funkcje mogą być wywoływane miliony razy, co powoduje, że wiele obiektów shared_ptr jest tworzonych i niszczonych. Oto fragment płaskiego profilu gprof z ostatniego biegu:
Each sample counts as 0.01 seconds. % cumulative self self total time seconds seconds calls s/call s/call name 9.74 295.39 35.12 2451177304 0.00 0.00 std::tr1::__shared_count::__shared_count(std::tr1::__shared_count const&) 8.03 324.34 28.95 2451252116 0.00 0.00 std::tr1::__shared_count::~__shared_count()
Więc, ~ 17% z runtime poświęcono na zliczanie referencji z obiektami shared_ptr. Czy to normalne?
Duża część mojej aplikacji jest jednowątkowa i myślałem o przepisaniu niektórych funkcji jako
void f( const Dataset& ds ) {...}
I zastępowanie połączeń
shared_ptr< Dataset > pds( new Dataset(...) );
f( pds );
Z
f( *pds );
W miejscach, gdzie wiem na pewno, że obiekt nie zostanie zniszczony, podczas gdy przepływ programu znajduje się wewnątrz f(). Ale zanim ucieknę, aby zmienić kilka podpisów funkcji / wywołań, chciałem wiedzieć, co typowy hit wydajności przechodzenia przez shared_ptr był. Wygląda na to, że shared_ptr nie powinien być używany do funkcji, które są wywoływane bardzo często.
Każdy wkład będzie mile widziany. Dzięki za przeczytanie.
-Artem
Update: Po zmianie kilku funkcji na accept const Dataset&
, nowy profil wygląda tak:
Each sample counts as 0.01 seconds. % cumulative self self total time seconds seconds calls s/call s/call name 0.15 241.62 0.37 24981902 0.00 0.00 std::tr1::__shared_count::~__shared_count() 0.12 241.91 0.30 28342376 0.00 0.00 std::tr1::__shared_count::__shared_count(std::tr1::__shared_count const&)
Jestem trochę zdziwiony tym, że liczba wywołań destruktora jest mniejsza niż liczba wywołań konstruktora kopiującego, ale ogólnie jestem bardzo zadowolony ze zmniejszeniem związanego z tym czasu pracy. Dzięki wszystkim za Rady.
5 answers
Zawsze podaj shared_ptr
przez const Referencja:
void f(const shared_ptr<Dataset const>& pds) {...}
void g(const shared_ptr<Dataset const>& pds) {...}
Edit: odnośnie kwestii bezpieczeństwa wymienionych przez innych:
- podczas korzystania z
shared_ptr
mocno w całej aplikacji, przekazywanie przez wartość zajmie ogromną ilość czasu(widziałem go 50+%). - Użyj
const T&
zamiastconst shared_ptr<T const>&
, gdy argument nie powinien być null. - używanie
const shared_ptr<T const>&
jest bezpieczniejsze niżconst T*
, gdy wydajność jest problemem.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-23 18:37:29
Potrzebujesz shared_ptr tylko po to, aby przekazać go do funkcji / obiektów, które przechowują go do wykorzystania w przyszłości. Na przykład, niektóre klasy mogą zachować shared_ptr do użycia w wątku roboczym. W przypadku prostych połączeń synchronicznych wystarczy użyć zwykłego wskaźnika lub odniesienia. shared_ptr nie powinien całkowicie zastępować zwykłych wskaźników.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-23 18:13:09
Jeśli nie używasz make_shared , możesz spróbować? Po zlokalizowaniu liczby referencji I obiektu w tym samym obszarze pamięci Można zobaczyć wzrost wydajności związany z spójnością pamięci podręcznej. Warto spróbować.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-23 18:14:12
W aplikacjach o krytycznym znaczeniu należy unikać tworzenia i niszczenia obiektów, szczególnie nadmiarowych.
Zastanów się, co robi shared_ptr. Nie tylko tworzy nowy obiekt i wypełnia go, ale także odwołuje się do udostępnionego stanu do inkrementacji informacji referencyjnych, a sam obiekt prawdopodobnie mieszka gdzieś indziej, co będzie koszmarne w pamięci podręcznej.
Prawdopodobnie potrzebujesz shared_ptr (ponieważ gdybyś mógł uciec od lokalnego obiektu, nie przydzieliłbyś jednego ze sterty), ale mógłbyś nawet "buforować" wynik dereferencji shared_ptr:
void fn(shared_ptr< Dataset > pds)
{
Dataset& ds = *pds;
for (i = 0; i < 1000; ++i)
{
f(ds);
g(ds);
}
}
...ponieważ nawet * pds wymaga uderzenia więcej pamięci niż jest to absolutnie konieczne.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-24 23:25:06
Wygląda na to, że naprawdę wiesz, co robisz. Sprofilowałeś swoją aplikację i wiesz dokładnie, gdzie są używane cykle. Rozumiesz, że wywołanie konstruktora do referencyjnego wskaźnika liczenia jest kosztowne tylko wtedy, gdy robisz to stale.
Jedyne informacje, które mogę ci dać to: Załóżmy, że wewnątrz funkcji f (t * ptr), jeśli wywołujesz inną funkcję, która używa współdzielonych wskaźników, i robisz inne(ptr), a inne tworzy współdzielony wskaźnik surowego wskaźnika. Kiedy ta sekunda liczba referencji współdzielonych wskaźników wynosi 0, a następnie skutecznie usuniesz obiekt....nawet jeśli nie chciałeś. mówiłeś, że często używałeś wskaźników, więc musisz uważać na takie przypadki.
edytuj:
Możesz uczynić Destruktor prywatnym i tylko przyjacielem klasy shared pointer, więc w ten sposób Destruktor może być wywołany tylko przez shared pointer, wtedy jesteś bezpieczny. nie zapobiega wielokrotnym usunięciom ze współdzielonych wskaźników. Zgodnie z komentarzem od Mat.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-24 18:52:34