2009-06-16 13 views
11

Mamy problemy z wydajnością, a jednym z potencjalnych winowajców jest scentralizowane wykorzystanie lotnego singletonu. specyficzny kod ma postaćJaki jest koszt zmiennego słowa kluczowego w systemie wieloprocesorowym?

class foo { 
    static volatile instance; 
    static object l = new object(); 

    public static foo Instance { 
    if (instance == null) 
     lock(l) { 
     if (instance == null) 
      instance = new foo(); 
     } 

    return foo(); 
    } 
} 

ten działa na polu 8-way, i widzimy kontekst przełączania w wysokości 500000 na sekundę. typowe zasoby systemowe są w porządku - 25% wykorzystania procesora, 25% wykorzystania pamięci, niskiego IO, braku stronicowania, itp.

czy używanie niestabilnego pola indukuje barierę pamięci lub jakiegokolwiek rodzaju ponowne ładowanie cpu? czy po prostu za każdym razem chodzi o pamięć główną tylko dla tego pola?

+0

nie, to instancja foo. – kolosy

+0

Nie jestem pewien, dlaczego to musi być niestabilne, ponieważ nie zmieniasz odniesienia. –

+0

Ja też nie - to czyjś kod, który debuguję. moim głównym pytaniem jest jednak, czy użycie niestabilnego tutaj może spowodować problemy z rywalizacją na wielordzeniowym pudełku x86 – kolosy

Odpowiedz

4

lock indukuje barierę pamięci, więc jeśli zawsze uzyskujesz dostęp do instancji w zamku, nie potrzebujesz zmiennej.

Według this site:

C# lotne narzędzia słów kluczowych nabywać i zwolnij semantykę, co implikuje bariera pamięci czytać dalej czytać i pisać na barierę pamięci zapisu.

+0

no - spójrz na kod. Teoretycznie blokada wystąpi tylko raz, ponieważ po tym ustawiona zostanie zmienna lotna, a kontrola zewnętrzna przejdzie. – kolosy

+0

że edycja robi różnicę na świecie :). dzięki. – kolosy

+1

Vance Morrison obejmuje również DCL w tym artykule MSDN - http://msdn.microsoft.com/en-us/magazine/cc163715.aspx –

1

Niestety, Singleton bierze złą reputację na prawie wszystko :)

To nie jest moja dziedzina wiedzy, ale o ile wiem, nie ma nic szczególnego lotnych innych niż kompilator/run -time NIE zmienia kolejność odczytu/zapisu (do zmiennej) dla celów optymalizacji.

Edycja: Stoję poprawiony. Nie tylko niestabilne wprowadzają bariery pamięci, ale to, co się dzieje (i przypadkowo, wydajność) zależy w dużej mierze od konkretnego procesora. Zobacz http://dotnetframeworkplanet.blogspot.com/2008/11/volatile-field-and-memory-barrier-look.html

Dlatego nadal potrzebujesz blokady.

pytania, które mogą/nie mogą być już odpowiedział:

  1. Jaki jest Twój Singleton instancji właściwie robi? Może kod instancji musi być refaktoryzowany ...
  2. Jaka jest liczba wątków uruchomionego procesu? 8-kierunkowe pudełko nie pomoże, jeśli masz wyjątkowo wysoką liczbę wątków.
  3. Jeśli jest wyższy niż oczekiwano, dlaczego?
  4. Co jeszcze działa w systemie?
  5. Czy problem z wydajnością jest spójny?
+0

1. niewiele. jest to kontener dla niektórych danych, które muszą być dostępne na całym świecie. 2. Liczba wątków jest wystarczająca. przełączanie kontekstów/sekundę jest absurdalnie wysokie. 500 000/s 3. dobre pytanie. 4. nic. 5. tak – kolosy

0

W tym przykładzie zmienność nie powinna być przedmiotem żadnego "spowolnienia". Blokada() może jednak wiązać się z ogromnymi obiegami do jądra, szczególnie jeśli istnieje wiele niezgody na blokadę.

Naprawdę nie ma potrzeby, aby zablokować singleton w tym przypadku można po prostu zrobić

class Foo { 
    static Foo instance = new Foo(); 
    public static Foo FooInstance() { 
    return instance ; 
    } 
} 

Oczywiście, jeśli „instancja” jest używany w wielu różnych wątków, wy mieliście jeszcze do lock() wszystko co zmienia Foo, chyba że wszystkie metody/właściwości Foo są tylko do odczytu. np.

class Foo { 
     static Foo instance = new Foo(); 
     object l = new object(); 
     int doesntChange = 42; 
     int canChange = 123; 
     public static Foo FooInstance() { 
     return instance ; 
     } 
     public void Update(int newVal) { 
     lock(l) { // you'll get a lot of trouble without this lock if several threads accesses the same FOO. Atleast if they later on read that variable 
      canChange = newVal; 
     } 

     public int GetFixedVal() { 
     return doesntChange; //no need for a lock. the doesntChange is effectivly read only 
     } 
    } 
0

Nie ma potrzeby używania niestabilnego dla singletonu, ponieważ ustawiasz go dokładnie raz - i blokowanie kodu ustawia. Aby uzyskać więcej informacji, patrz Jon Skeet's article on singletons.

+0

DCL bez bariery pamięci przy odczycie to "Trzecia wersja - próba (i nie powiodła się) bezpieczeństwo wątków przy użyciu podwójnego sprawdzania blokady. * Bez barier pamięciowych, jest on również łamany w specyfikacji ECMA CLI. * ". Kod OPs jest nieparzysty, ponieważ może zwracać * wiele * foo (zamiast zwracać 'instancję', która reprezentuje * inny problem *). Ten stary post (2006) nic nie wskazuje na to, że DCL * bez pamięci * jest bezpieczne dla singletonów (znowu błąd w kodzie ...?) – user2864740

+0

http://benbowen.blog/post/cmmics_iii/ - patrz uwaga na temat ".NET memory model 2.0" "gwarantuje". – user2864740

3

Jedną z rzeczy, których nie da się zmienić, jest zmiana kontekstu. Jeśli widzisz 500 000 przełączeń kontekstu na sekundę, oznacza to, że twoje wątki blokują coś i są niestabilne.

0

Krótka odpowiedź brzmi: Tak, tworzy barierę pamięci (wypiera wszystko i przechodzi do głównej pamięci, a nie tylko tej pojedynczej zmiennej), ale nie, nie będzie przyczyną przełączania kontekstu.

Ponadto, jak już wspomnieli inni, nie uważam, że lotny jest tutaj konieczny.

+0

'lotny' jest konieczny do * gwarancji * bezpieczeństwa wątków (nie jest to jedyna opcja, ale jest wymagana w podstawowym wzorze singleton DCL). Zapobiega ponownemu porządkowaniu (i zapewnia "nietradycyjny" odczyt), gdy kod * nie * pozyskuje blokady: jeżeli kod * zawsze * wszedł do zamka, nie byłoby korzyści "lotności". – user2864740

Powiązane problemy