2012-07-22 12 views
12

Przeszedłem przez zestaw kilku niespodzianek, jeśli chodzi o wdrażanie Kolejki dla systemu wielowątkowego. Oto: -Zsynchronizowany z ReentrantLock na wydajności

Scenariusz: - 1 producent, 1 konsument: - Producent wstawia liczbę całkowitą do kolejki. Konsument po prostu usuwa go z kolejki.

Podstawową strukturą danych z kolejki: - TreeSet (które nigdy nie myślałem, że będę używał), LinkedList, LinkedBlockingQueue (o nieokreślonej wielkości)

Kod: - z TreeSet jako kolejki: -

while (i < 2000000) { 
     synchronized (objQueue) { 

      if (!(objQueue.size() > 0)) { 
       try { 
        objQueue.wait(); 
       } catch (InterruptedException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } 
      } 
      Integer x = objQueue.first(); 
      if (x != null) { 
       objQueue.remove(x); 
       ++i; 
      } 
     } 
    } 

EDIT: -

 while (i < 2000000) { 
     synchronized (objQueue) { 
      objQueue.add(i); 
      ++i; 
      objQueue.notify(); 
     } 
    } 

Dla LinkedBlockingQueue: -

 while (i < 2000000){ 
     try { 
      objQueue.put(i); 
      ++i; 
     } catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      Thread.currentThread().interrupt(); 
     } 
    } 

     while (i < 2000000) { 
     try { 
      objQueue.take(); 
      ++i; 

     } catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      Thread.currentThread().interrupt(); 
     } 
    } 

Dla LinkedList: - podobny kod zsynchronizowany.

następujące pytania: -

1) Gdy mierzono wydajność poprzez Wizualnej VM, to obserwuje się, że do kodu producenta, TreeSet działa lepiej niż LinkedBlockingQueue i LinkedList, mimo że zajmuje O (log n) , tworzenie obiektów w strukturach Powiązanych jest znacznym obciążeniem. Dlaczego teoria różni się od praktyki? Dlaczego preferujemy struktury Połączone, Macierzowe nad strukturami Drzew w implementacjach kolejkowych?

2) Zsynchronizowany jest wyraźnym zwycięzcą w stosunku do ReeentrantLock, ponieważ TreeSet działał lepiej niż LinkedList, który działał lepiej niż LinkedBlockingQueue. Chciałbym móc dołączyć wyniki Visual VM. To nie jest w głosami artykule http://www.ibm.com/developerworks/java/library/j-jtp10264/index.html

operacje są wykonywane na

Dell Vostro 1015, Core 2 Duo 2.10, 2GB RAM z 32-bitowym systemem operacyjnym iz

JVM: Java HotSpot (TM) Client VM (20,1-B02, tryb mieszany) Java: wersja 1.6.0_26, sprzedawca Sun Microsystems Inc.

Odpowiedz

13

1.ReentrantLock mogą być bardziej skłonni do korzystania, jeśli trzeba zaimplementować wątku, który przechodzi przez połączoną listę, blokując następny węzeł, a następnie odblokowując bieżący węzeł.

2.Synchronized słowo kluczowe jest trafne w sytuacji takiej jak blokada coarsening, zapewnia adaptacyjną przędzenia, blokowanie tendencyjne i potencjał do zamka elizji poprzez analizę ewakuacyjnej. Te optymalizacje nie są obecnie wdrażane dla ReentrantLock.

Dla właściwego porównania wydajności zobaczyć:

http://lycog.com/concurency/performance-reentrantlock-synchronized/

+0

To prawie ten sam przykład, do którego dołączyłem link w moim pytaniu. Mówi mi, że wydajność REL jest lepsza niż synchronizacja zaczynająca się od 2 wątków. Czuję też, że jeśli uda mi się zmusić program planujący OS do uruchamiania wątków na wszystkich dostępnych procesorach, zdecydowanie poprawimy wydajność dla LinkedBlockingQueues. Jeśli potrzebujesz moich danych obserwacji, daj mi znać. – 100pipers

+2

Kumar zapomniał wspomnieć, że wziął odpowiedź od [Weblog Davida Dice'a] (https://blogs.oracle.com/dave/entry/java_util_concurrent_reentrantlock_vs). –

+0

@AlexanderRyzhov dziękuję za pozwolenie mi wskazać oryginalnego autora tego artykułu, jak to przeczytałem, podczas gdy przygotowywałam się do mojego scjp z innych blogów ... bardzo dziękuję –

4
  1. Ponieważ punktem odniesienia jest błędna: w prawdziwym przypadków użycia, czas potrzebny do produkcji i konsumpcji elementów z kolejki jest o wiele ważniejsze niż czas potrzebny na dodanie i usunięcie elementu do/z kolejki. Tak więc nieprzetworzona wydajność kolejki nie jest tak ważna. BTW, kod pokazuje tylko sposób pobierania elementów z pierwszej implementacji kolejki, a nie sposób ich dodawania. Co więcej, wybór właściwej struktury nie jest dokonywany w oparciu o wydajność, ale zachowanie. Jeśli chcesz coś współbieżnego, wybierasz kolejkę blokującą, ponieważ jest zaimplementowana i nie ma błędów takich jak twój kod. Jeśli chcesz FIFO (który jest często tym, czego chcesz), nie wybierzesz TreeSet.

  2. Jeśli chcesz porównać zsynchronizowane z ReentrantLock, nie powinieneś używać jednej struktury danych dla jednej i innej struktury danych dla drugiej. ReentrantLock był szybszy, ale obecnie jest na tym samym poziomie (jeśli wierzę w to, co Brian Goetz mówi w JCIP). W każdym razie wybrałbym jeden z drugim ze względów bezpieczeństwa/możliwości. Nie ze względu na wydajność.

+0

Nie zgadzam się z tym, że Kryteria decyzji nie powinny uwzględniać wyników. Typowym podejściem byłoby prawidłowe działanie rozwiązania, a następnie rozważenie wydajności. Ale nie ma absolutnie nic złego w rozważaniu tego z góry, ponieważ może to pomóc w późniejszym oszczędzaniu czasochłonnego refaktoryzacji. – Brady

+0

@JB Nizet: - Jaki błąd zawiera mój kod? Mam podobne rozumienie, że dla FIFO nie powinienem używać TreeSet, ale proszę podać mi powód, dla którego metoda umieszczania TreeSet jest znacznie szybsza niż metoda add obiektu LinkedList (ponieważ czas budowy obiektu jest wysoki), dlaczego nie używam zestawu TreeSet (chociaż usuwanie jest bardzo szybkie w przypadku obiektu LinkedList)? W przypadku aplikacji do handlu w czasie rzeczywistym liczy się tylko wydajność. A więc sedno tej historii polega na tym, że chcę użyć lepszego DS dla Queue i chcę używać REL przez synchronizację. – 100pipers

+1

@Brady Oczywiście, nie zaczynaj od głupiego projektu, który oczywiście będzie źle działać, ale nie powinieneś wybierać konkretnej implementacji opartej na przeczuciu wydajności. Wybierz ten, który najlepiej pasuje do potrzeb Twojej aplikacji, a będziesz miał znacznie mniej błędów. Jeśli i tylko wtedy, gdy wydajność staje się * problemem *, poszukaj sposobów ulepszenia go poprzez zamianę implementacji. – Bohemian

Powiązane problemy