2009-07-07 14 views
35

Wiem, że pisanie do zmiennej volatile powoduje jej opróżnienie z pamięci całego procesora, ale chcę wiedzieć, czy odczyt zmiennej lotnej jest tak szybki, jak odczytuje normalnie?Czy zmienna lotna "czyta" tak szybko, jak normalnie czyta?

Czy zmienne mogą być kiedykolwiek umieszczane w pamięci cpu procesora lub czy zawsze są pobierane z pamięci głównej?

+1

Czy możesz dodać "java" gdzieś w pytaniu? Nie było zamieszania z C - samo ustawienie słowa kluczowego wydaje się niewystarczające. –

+0

wydaje się być tam teraz – pdeva

Odpowiedz

-3

volatile oznacza, że ​​kompilator nie może zoptymalizować zmiennej, umieszczając jej wartość w rejestrze procesora. Musi być dostępny z pamięci głównej. Może być jednak umieszczony w pamięci podręcznej procesora. Pamięć podręczna zapewni konsystencję między dowolnymi innymi procesorami/rdzeniami w systemie. Jeśli pamięć jest zmapowana do IO, wtedy sprawy są nieco bardziej skomplikowane. Jeśli został zaprojektowany jako taki, sprzęt uniemożliwi buforowanie tej przestrzeni adresowej, a wszystkie dostępy do tej pamięci zostaną przesłane do sprzętu. Jeśli nie ma takiego projektu, projektanci sprzętu mogą wymagać dodatkowych instrukcji procesora, aby zapewnić, że odczyt/zapis przechodzi przez pamięci podręczne, itp.

Zazwyczaj słowo kluczowe "zmienny" używane jest tylko w przypadku sterowników urządzeń w działaniu systemy.

+6

To może być coś, co jest niestabilne w C, ale to nie jest to, co to oznacza w Javie. W Javie zmienność polega na tym, czy jeden wątek wykonujący odczyt "zobaczy" zmiany dokonane przez inny wątek. To więcej niż tylko to, czy wartość może znajdować się w rejestrze procesora. Zmienne słowo kluczowe zapobiega także temu, jakiego rodzaju zmiana kolejności JVM może dokonać w kodzie używającym zmiennej. – NamshubWriter

+0

Oto artykuł dr Dobba, który zawiera trochę więcej szczegółów między różnicami: http://www.ddj.com/hpc-high-performance-computing/212701484 –

+0

Czytelnik nie powiedział java i został konkretnie wymieniony na drugim poziomie Pamięć podręczna, więc założyłem najczęściej występujący scenariusz ... C. – drudru

13

Odpowiedź jest nieco zależna od architektury. Na architekturze x86 nie ma dodatkowego narzutu związanego z lotnymi odczytami, choć istnieją implikacje dla innych optymalizacji.

JMM cookbook from Doug Lea, see architecture table near the bottom.

Dla wyjaśnienia: Nie ma żadnego dodatkowego obciążenia związane ze się czytać. Bariery pamięci stosowane są w celu zapewnienia właściwego porządku. JSR-133 klasyfikuje cztery bariery "LoadLoad, LoadStore, StoreLoad i StoreStore". W zależności od architektury niektóre z tych barier odpowiadają "no-op", co oznacza, że ​​nie podejmuje się żadnych działań, inne wymagają ogrodzenia. Nie ma żadnych niejawnych kosztów związanych z samym obciążeniem, chociaż można go ponieść, jeśli na miejscu znajduje się ogrodzenie. W przypadku x86 tylko bariera StoreLoad powoduje powstanie ogrodzenia.

Jak wskazano w poście na blogu, fakt, że zmienna jest niestabilna, oznacza, że ​​istnieją założenia dotyczące natury zmiennej, która nie może być już wykonana, a niektóre optymalizacje kompilatora nie zostałyby zastosowane do zmiennej.

Niestabilność nie jest czymś, co należy stosować płynnie, ale nie należy się jej również obawiać. Istnieje wiele przypadków, w których niestabilna wola zastąpi bardziej rygorystyczne blokowanie.

+2

Jak to możliwe? A co z procesorami wielordzeniowymi? (Bez czytania całego opublikowanego linku) – ripper234

+6

Nic nie jest nigdy "opcją", chyba że można ją całkowicie wyeliminować z programu. Lotne odczyty są tanie, ale nie wolne i hamują optymalizację w taki sposób, że nie czyta się zwykłych odczytów (np. Nie można wyciągnąć lotnych odczytów z pętli lub odczytać z rejestru). "No-op" w tym przypadku odnosi się do braku odpowiedniej instrukcji fence, ale sam odczyt ma semantykę, a te mają koszt. –

+2

Prawidłowo. Są to jednak semantyka optymalizacji, która leży poza tymi narzuconymi przez zmienność jawnie. Główna odpowiedź na to pytanie brzmi: "Jest zależna od architektury". Na razie komentarz jest prawdziwy. Wiele osób boi się niestabilności i jest to trochę głupie. Chociaż ja też nigdy nie polecałbym glibly używając lotnych na wszystko. –

0

Niestabilne odczyty nie mogą być tak szybkie, szczególnie w przypadku wielordzeniowych procesorów (ale także pojedynczych rdzeni). Wykonujący rdzeń musi pobrać z faktycznego adresu pamięci, aby upewnić się, że otrzymuje aktualną wartość - rzeczywiście nie można buforować zmiennej.

W przeciwieństwie do innej odpowiedzi tutaj, zmienne zmienne to nie używane tylko dla sterowników urządzeń! Są one niekiedy niezbędne do napisania wielowątkowego kodu o wysokiej wydajności!

+5

* Niestabilne odczyty nie mogą być tak szybkie, szczególnie w przypadku procesorów wielordzeniowych * nie jest to prawdą, na większości sprzętowych odczytów ulotnych to tylko normalne obciążenia. Obciążenia są drogie, gdy brakuje pamięci podręcznej, ale ulotne odczyty nie trafiają do pamięci głównej, jeśli w pamięci podręcznej znajduje się wartość, a nawet ulotne zapisy (które są drogie) mogą aktualizować lokalne linie pamięci podręcznej procesora. Multi CPU/Socket zależy od protokołu koherencji pamięci podręcznej, aby zapewnić prawidłowe wartości, ale nie powoduje, że ulotne odczyty są droższe. – bestsss

+0

@bestsss - cóż, przyznaję niewiedzę do szczegółów, ale zawsze uczono mnie, że normalne odczyty "zawsze" przewyższają niestabilne odczyty. Nie postawię 1 miliarda dolarów na odpowiedź. – ripper234

+0

Nie, niektóre cpusy mogą potrzebować bariery obciążeniowej, ale wciąż tanie. Z reguły kciuk uważa lotne odczyty za zwykłe ładunki. Jeśli jakikolwiek procesor musi przejść do głównej pamięci (aka miss pamięci), jest to przerażająca wada projektu. – bestsss

1

Jest zależny od architektury. To, co robi volatile, oznacza, że ​​kompilator nie optymalizuje tej zmiennej. Zmusza większość operacji do traktowania stanu zmiennej jako nieznanego. Ponieważ jest niestabilny, może zostać zmieniony przez inny wątek lub inną operację sprzętową. Tak więc, odczyty będą musiały ponownie przeczytać zmienną, a operacje będą wykonywane w rodzaju odczytu-modyfikacji-zapisu.

Ten rodzaj zmiennej jest używany do sterowników urządzeń, a także do synchronizacji z muteksami/semaforami w pamięci.

+3

Nie dotyczy, pytanie dotyczy Javy. – ripper234

+2

Wciąż jest istotne, jeśli rozumiesz, co oznacza zmienność. – sybreon

+0

To oznacza coś nieco innego w Javie. – ripper234

16

Powinieneś naprawdę sprawdzić ten artykuł: http://brooker.co.za/blog/2012/09/10/volatile.html.Artykuł na blogu przekonuje, że lotne odczyty mogą być dużo wolniejsze (także dla x86) niż nielotne odczyty na x86.

  • Test 1 jest równoległym odczytem i zapisem dla zmiennej nielotnej. Tam nie jest mechanizmem widoczności, a wyniki odczytów są potencjalnie nieaktualne.
  • Test 2 jest równoległym odczytem i zapisem dla zmiennej lotnej. Nie odnosi się to konkretnie do pytania PO. Warto jednak zauważyć, że zmienna lotność może być bardzo powolna.
  • Test 3 jest odczytywany jako lotny w ciasnej pętli. Wykazano, że semantyka tego, co oznacza niestabilność, wskazuje, że wartość może się zmieniać przy każdej iteracji pętli. W ten sposób JVM nie może zoptymalizować odczytu i wyciągnąć go z pętli. W teście 1 jest prawdopodobne, że wartość została raz odczytana i zapisana, a zatem nie ma faktycznego "odczytu".

Marc Booker's tests

zgłosił Marc Bookera za prowadzenie tych badań.

+1

, które wydaje się mieć miejsce tylko wtedy, gdy występuje niestabilność. – pdeva

+6

@pdeva, nie, na wykresie wyraźnie widać, że nieprzewidziany lotny odczyt jest wolniejszy niż nielotny. Przykuwa wzrok, wygląda 2-3 razy wolniej. – nilskp