2009-10-12 13 views
7

Używam współdzielonych wskaźników dla czasu ukojenia teraz, i mam problemy z wydajnością w moim programie ... Chciałbym wiedzieć, czy wskaźniki dzielone prowadzą do spadku wydajności. Jeśli tak, to jak ciężko? Wielkie dzięki.Współdzielone wskaźniki i wydajność

Mój program jest wielowątkowy, używając std :: tr1 :: shared_ptr

+6

Heh. Brak odpowiedzi tutaj, ale po prostu uwielbiałem sposób, w jaki tytuł został sformułowany. Wyobrażam sobie procesor wykonujący instrukcje wesoło, kiedy nagle widzi on instrukcję współdzielonego wskaźnika na końcu potoku. "O nie, to będzie huuuuurt ...... OW!" –

+0

Co sprawia, że ​​problem polega na udostępnianiu wskaźników? –

+0

Mając ludzi mówiących, że marnują czas procesora, to jest to: P – Guest

Odpowiedz

4

Shared wskaźniki są odniesienia zliczane. Szczególnie w przypadku korzystania z wielowątkowości, inkrementacji i dekrementacji licznik odwołań może zająć znaczną ilość czasu. Powodem, dla którego wielowątkowość boli, jest to, że przekazałeś współdzielony wskaźnik między wątkami, licznik odwołań zostanie podzielony między te wątki, więc każda manipulacja musi zostać zsynchronizowana między wątkami. To może trochę spowolnić.

Edycja: Dla tych, którzy dbają o to, jak wolniejsze blokowanie gwintów może wykonać dość proste operacje, zobacz testowanie Suttera za pomocą kilku implementacji CoW Strings. Chociaż jego testowanie jest dalekie od doskonałości (np. Testował tylko w systemie Windows), nadal daje pewne wyobrażenie na temat rodzaju spowolnienia, jakiego można się spodziewać. W większości praktycznych celów możesz/mógłbyś wymyślić ciąg CoW jako coś takiego jak shared_ptr<charT>, z wieloma (nieistotnymi) funkcjami członków dodanymi.

+0

Jest to prawdziwe tylko wtedy, gdy używasz mechanizmu liczenia odwołań, który zna wątek. Nie wydaje się, aby tak było, zgodnie z dokumentacją http://www.boost.org/doc/libs/1_38_0/libs/smart_ptr/shared_ptr.htm#ThreadSafety – JaredPar

+2

Nie mówi, z czego korzysta shared_ptr. Niektóre z nich już znają wątek, a inne nie. Otwarte jest pytanie, czy ten, którego używa, czy nie. Powiedział, że masz rację, że szanse na to, że przyczyną problemu z wydajnością są dość odległe. –

+0

Dodano więcej informacji – Guest

10

Jest praktycznie niemożliwe, aby poprawnie odpowiedzieć na to pytanie, biorąc pod uwagę dane. Jedynym sposobem, aby naprawdę powiedzieć, co powoduje problem z wydajnością w aplikacji, jest uruchomienie profilera w programie i sprawdzenie danych wyjściowych.

Jest to mało prawdopodobne, aby funkcja shared_ptr powodowała spowolnienie. Typ shared_ptr i wiele wczesnych odmian domowych są używane w coraz większej liczbie programów w C++. Ja sam używam ich w mojej pracy (zawodowej w domu). Spędziłem dużo czasu na profilowaniu moich aplikacji roboczych, a shared_ptr nigdy nie było nawet blisko problemu z moim kodem lub innym kodem uruchomionym w aplikacji. Bardziej prawdopodobne jest, że błąd jest gdzie indziej.

3

Bardzo mało prawdopodobne - musiałbyś spędzić większość czasu na przekazywaniu wskaźników.

Efekt wspólnych ptr jest zwykle niewielki i ciężko jest nawet skonstruować przypadek krawędzi, w którym stają się problemem (zakładając odpowiednią implementację i odpowiednio optymalizujący kompilator).

Wpływ wspólnego ptr:

  • zwiększona wielkość przydziału. Ma to znaczenie tylko wtedy, gdy masz wiele współdzielonych wskaźników dla bardzo małych obiektów (powiedzmy, dziesiątki milionów shared_ptr<int>) i/lub pracują w pobliżu limitu pamięci. Istnieje niewielka możliwość zauważalnego spadku wydajności, jeśli dodatkowe przydziały przekracza poziom pamięci podręcznej/NUMA wewnątrz pętli wewnętrznej

  • zwiększoną numer alokacji
    shared_ptr allcoates śledzony obiekt (liczba odniesienia słaby liczbę i deleter) . To powoduje presję na stertę i może spowodować ogólne spowolnienie, jeśli masz dużą całkowitą liczbę przydziałów i zwolnień.
    można uniknąć stosując make_shared, stawiając referent i trackng obiektu do pojedynczego przydziału

  • licznik odniesień
    zwiększa koszt kopię wskaźnika. W aplikacji z pojedynczym wątkiem zauważysz, że i tak tylko Ty spędzasz większość czasu na kopiowaniu wskaźników. W aplikacji wielowątkowej nadal potrzebujesz dużej rywalizacji o te same wskaźniki.
    Kosztu kopii można uniknąć w wielu miejscach, przekazując np. shared_ptr<T> const &, np. jako argument funkcji.

  • dereferencing
    Dodatkowy koszt dereferencing wynosi zero w produkcji uwalniania kompilatora. Wersje debugowania często odpowiadają wywołaniom funkcji i dodatkowym kontrolom NULL. Wciąż jednak, szczególnie w kompilacjach debugujących, większość wskazówek dotyczących odwołań do konferencji musiałaś poświęcić na to, aby coś zmienić.


Bez dodatkowego informaiton, nie możemy pomóc. Musisz opisać, czym są "problemy z wydajnością" (ogólne spowolnienie, niektóre operacje zabierają dużo czasu, wiele zmian) i kilka kluczowych liczb - jaka jest Twoja aplikacja, ile inteligentnych wskaźników tam jest, jak często są kopiowane, i jakie inne operacje prowadzisz besindse żonglując inteligentnymi wskaźnikami.

Albo nauczysz się używać monitora wydajności i/lub profilera, aby dowiedzieć się, co powoduje spowolnienia i czy występują szczególne wąskie gardła.

5

Jeśli twój program wydaje się mieć problem z wydajnością, to zupełnie naturalne, aby zacząć odgadywanie, jaki może być problem, ale jeśli chcesz postawić zakład, to prawie w 100% prawdopodobnie będzie to coś zupełnie innego. Profilowanie może znaleźć problem. This is the method I use.

0

Jedną z rzeczy, która może zaszkodzić wydajności, jest nadmierne przekazywanie shared_ptr jako parametrów funkcji. Rozwiązaniem tego problemu byłoby przekazywanie odniesień do shared_ptr. Jednak jest to mikro-optymalizacja, więc tylko zrobić to, gdy naprawdę potrzebne

edit: Myśląc o tym, że są lepsze sposoby optymalizacji:

  • Kiedy nadmierne przechodzącej wskaźnik, powinieneś pozwolić obiekt robi coś zamiast go przeciągać.
  • można przekazać (const) referencję do obiektu, zamiast wskaźnika
  • przekazać odniesienie do wskaźnika, gdy wskaźnik musi być zmieniony
12

Jeśli aplikacja przekazuje około 700 bajtów wiadomości XML, które mogą być zawarte w 65-bajtowych komunikatach protokołu Google lub 85-bajtowych komunikatach ASN.1, prawdopodobnie to nie będzie miało znaczenia. Ale jeśli przetwarza milion razy na sekundę, to nie odrzucałbym kosztów dodawania 2 cykli pełnego odczytu do modyfikacji zapisu (RMW) do przejścia wskaźnika.

Pełny odczyt zmodyfikować zapisu jest rzędu 50 ns, więc dwa jest 100 ns. Koszt ten jest kosztem zamka i zamknięcia-dek - taki sam jak 2 CAS. Jest to połowa rezerwy i wydania sekcji krytycznej systemu Windows.Jest to porównywane z jednym naciśnięciem cyklu maszynowego (400 PICO sekund na maszynie 2,5 GHz).

Nie obejmuje to również innych kosztów związanych z unieważnieniem linii pamięci podręcznej, która faktycznie zawiera licznik, skutków blokady magistrali BUS na innych procesorach itp.

Przekazywanie inteligentnych wskaźników przez odniesienie do stałych jest prawie ZAWSZE preferowane. Jeśli użytkownik nie utworzy nowego współdzielonego wskaźnika, gdy chce zagwarantować lub kontrolować - czas życia pointee , to jest to błąd w kamerze. Chcąc nie chcąc przechodzić do bezpiecznego wątku, licząc inteligentne wskaźniki wokół wartości, wystarczy zapytać o trafienia wydajnościowe.

Używanie odnośników zliczanych wskaźników upraszcza życie bez wątpienia, ale przekazywanie dzielonych wskaźników przez wartość, aby próbować chronić się przed wadami w kręgu jest czystym i kompletnym nonsensem.

Nadmierne korzystanie z licznika referencyjnego może w krótkim czasie zamienić uproszczony program, który może przetwarzać 1mm wiadomości na sekundę (mps) na gruby, który obsługuje 150k/s na tym samym sprzęcie. Nagle potrzebujesz pół szafy serwerów i 10000 USD/rok energii elektrycznej.

Zawsze lepiej sobie radzisz, jeśli możesz zarządzać życiem obiektów bez liczenia referencji.

Przykładem prostego ulepszenia jest, powiedzmy, czy masz zamiar rozchodzić się po obiekcie i znasz szerokość fanouta (powiedzmy n) przyrostu, a raczej indywidualny przyrost przy każdym fanoucie.

BTW, gdy procesor widzi prefiks blokady, naprawdę mówi "nie, to boli".

Wszystko to, co się mówi, zgadzam się z każdym, że powinieneś zweryfikować hot spot.