Frage

Wie viel ist von ThreadLocal Variable liest langsamer als von normalen Bereich?

Konkreter ist einfach Objekterstellung schneller oder langsamer als der Zugriff Variable ThreadLocal?

Ich gehe davon aus, dass es schnell genug ist, so dass ThreadLocal<MessageDigest> Instanz mit viel schneller ist dann jedes Mal Instanz MessageDigest zu schaffen. Aber ist das auch für Byte gilt [10] oder byte [1000] zum Beispiel?

Edit: Die Frage ist, was wirklich vor sich geht, wenn Aufruf ThreadLocal die bekommen? Wenn das ist nur ein Feld, wie jede andere, dann würde Antwort sein: „Es ist immer am schnellsten“, nicht wahr?

War es hilfreich?

Lösung

nicht veröffentlichtes Benchmarks, ThreadLocal.get dauert etwa 35 Zyklen pro Iteration auf meinem Rechner. Nicht sehr viel. In Sun-Implementierung eine benutzerdefinierte lineare Sondieren Hashzuordnung in Thread Karten ThreadLocals auf Werte. Weil es immer nur von einem einzigen Thread zugegriffen wird, kann es sehr schnell sein.

Zuordnung von kleinen Objekten eine ähnliche Anzahl von Zyklen dauern, obwohl wegen der Cache Erschöpfung kann man etwas niedrigere Zahlen in einer engen Schleife erhalten.

Bau von MessageDigest ist wahrscheinlich relativ teuer sein. Es hat eine angemessene Menge von Staat und Bau geht durch den Provider SPI-Mechanismus. Sie können zum Beispiel zur Optimierung der Lage sein, das Klonen oder die Provider bereitstellt.

Nur weil es in einem ThreadLocal zu Cache schneller kann nicht zu schaffen, bedeutet nicht zwangsläufig, dass die Systemleistung erhöht. Sie werden zusätzliche Gemeinkosten zu GC bezogen haben, die nach unten alles verlangsamt.

Es sei denn, Ihre Anwendung sehr stark verwendet MessageDigest Sie stattdessen eine herkömmliche Thread-sichere Cache vielleicht prüfen verwendet wird.

Andere Tipps

Im Jahr 2009 einig JVMs Thread mit einem unsynchronisierten HashMap im Thread.currentThread () Objekt implementiert. Das machte es sehr schnell (wenn auch nicht annähernd so schnell wie ein reguläres Feld Zugang, natürlich mit), sowie sicherzustellen, dass der Thread Objekt wurde aufgeräumt, wenn das Thema gestorben. Aktualisierung diese Antwort im Jahr 2016, so scheint es, die meisten (alle?) Neuere JVMs verwenden, um eine ThreadLocalMap mit linearer Sondierung. Ich bin unsicher über die Leistung die, - aber ich kann nicht vorstellen, es ist deutlich schlechter als die frühere Implementierung

.

Natürlich new Object () ist auch sehr schnell in diesen Tagen, und die Müllsammler sind auch sehr gut auf kurzlebige Objekte Rückgewinnung.

Wenn Sie nicht sicher sind, dass die Objekterstellung teuer sein wird, oder Sie müssen einig Zustand auf einem Faden um Faden Basis bestehen bleiben, sind Sie besser dran, für das Gehen einfaches zuweisen, wenn Lösung benötigt wird, und Schalt nur über zu einem Thread Implementierung, wenn ein Profiler sagt Ihnen, dass Sie benötigen.

Gute Frage, ich habe mich gefragt, dass vor kurzem. Um Ihnen bestimmte Zahlen, die Benchmarks unten (in Scala, kompiliert praktisch den gleichen Bytecode als das Äquivalent von Java-Code):

var cnt: String = ""
val tlocal = new java.lang.ThreadLocal[String] {
  override def initialValue = ""
}

def loop_heap_write = {                                                                                                                           
  var i = 0                                                                                                                                       
  val until = totalwork / threadnum                                                                                                               
  while (i < until) {                                                                                                                             
    if (cnt ne "") cnt = "!"                                                                                                                      
    i += 1                                                                                                                                        
  }                                                                                                                                               
  cnt                                                                                                                                          
} 

def threadlocal = {
  var i = 0
  val until = totalwork / threadnum
  while (i < until) {
    if (tlocal.get eq null) i = until + i + 1
    i += 1
  }
  if (i > until) println("thread local value was null " + i)
}

hier wurden auf einem AMD 4x 2,8 GHz Dual-Cores und einem Quad-Core i7 mit Hyperthreading (2,67 GHz) durchgeführt wird.

Dies sind die Zahlen:

i7

Specs: Intel i7 2x Quad-Core @ 2,67 GHz Test: scala.threads.ParallelTests

Testname: loop_heap_read

Thread num .: 1 Gesamtzahl Tests: 200

Laufzeiten: (zeige letzten 5)  9,0069 9,0036 9,0017 9,0084 9,0074 (avg = 9,1034 min = 8,9986 max = 21,0306)

Thread num .: 2 Gesamtzahl Tests: 200

Laufzeiten: (zeige letzten 5)  4,5563 4,7128 4,5663 4,5617 4,5724 (avg = 4,6337 min = 4,5509 max = 13,9476)

Thread num .: 4 Gesamtzahl Tests: 200

Laufzeiten: (zeige letzten 5)  2,3946 2,3979 2,3934 2,3937 2,3964 (avg = 2,5113 min = 2,3884 max = 13,5496)

Thread num .: 8 Gesamtzahl Tests: 200

Laufzeiten: (zeige letzten 5)  2,4479 2,4362 2,4323 2,4472 2,4383 (avg = 2,5562 min = 2,4166 max = 10,3726)

Testname: Thread

Thread num .: 1 Gesamtzahl Tests: 200

Laufzeiten: (zeige letzten 5)  91,1741 90,8978 90,6181 90,6200 90,6113 (avg = 91,0291 min = 90,6000 max = 129,7501)

Thread num .: 2 Gesamtzahl Tests: 200

Laufzeiten: (zeige letzten 5)  45,3838 45,3858 45,6676 45,3772 45,3839 (avg = 46,0555 min = 45,3726 max = 90,7108)

Thread num .: 4 Gesamtzahl Tests: 200

Laufzeiten: (zeige letzten 5)  22,8118 22,8135 59,1753 22,8229 22,8172 (avg = 23,9752 min = 22,7951 max = 59,1753)

Thread num .: 8 Gesamtzahl Tests: 200

Laufzeiten: (zeige letzten 5)  22,2965 22,2415 22,3438 22,3109 22,4460 (avg = 23,2676 min = 22,2346 max = 50,3583)

AMD

Specs: AMD 8220 4x Dual-Core @ 2,8 GHz Test: scala.threads.ParallelTests

Testname: loop_heap_read

Insgesamt Arbeit: 20000000 Gewinde num .: 1 Gesamtzahl Tests: 200

Laufzeiten: (zeige letzten 5)  12,625 12,631 12,634 12,632 12,628 (avg = 12,7333 min = 12,619 max = 26,698)

Testname: loop_heap_read Die Gesamtleistung: 20000000

Laufzeiten: (zeige letzten 5)  6,412 6,424 6,408 6,397 6,43 (avg = 6,5367 min = 6,393 max = 19,716)

Thread num .: 4 Gesamtzahl Tests: 200

Laufzeiten: (zeige letzten 5)  3,385 4,298 9,7 6,535 3,385 (avg = 5,6079 min = 3,354 max = 21,603)

Thread num .: 8 Gesamtzahl Tests: 200

Laufzeiten: (zeige letzten 5)  5,389 5,795 10,818 3,823 3,824 (avg = 5,5810 min = 2,405 max = 19,755)

Testname: Thread

Thread num .: 1 Gesamtzahl Tests: 200

Laufzeiten: (zeige letzten 5)  200,217 207,335 200,241 207,342 200,23 (avg = 202,2424 min = 200,184 max = 245,369)

Thread num .: 2 Gesamtzahl Tests: 200

Laufzeiten: (zeige letzten 5)  100,208 100,199 100,211 103,781 100,215 (avg = 102,2238 min = 100,192 max = 129,505)

Thread num .: 4 Gesamtzahl Tests: 200

Laufzeiten: (zeige letzten 5)  62,101 67,629 62,087 52,02155,766 (avg = 65,6361 min = 50,282 max = 167,433)

Thread num .: 8 Gesamtzahl Tests: 200

Laufzeiten: (zeige letzten 5)  40,672 74,301 34,434 41,549 28,119 (avg = 54,7701 min = 28,119 max = 94,424)

Zusammenfassung

Lokal Ein Thread ist um 10-20x dass die Halde lesen. Es scheint auch gut auf dieser JVM Implementierung und diese Architekturen mit der Anzahl der Prozessoren skaliert wird.

Hier geht es einen weiteren Test. Die Ergebnisse zeigen, dass Thread etwas langsamer als ein normales Feld ist, aber in der gleichen Reihenfolge. Ca. 12% langsamer

public class Test {
private static final int N = 100000000;
private static int fieldExecTime = 0;
private static int threadLocalExecTime = 0;

public static void main(String[] args) throws InterruptedException {
    int execs = 10;
    for (int i = 0; i < execs; i++) {
        new FieldExample().run(i);
        new ThreadLocaldExample().run(i);
    }
    System.out.println("Field avg:"+(fieldExecTime / execs));
    System.out.println("ThreadLocal avg:"+(threadLocalExecTime / execs));
}

private static class FieldExample {
    private Map<String,String> map = new HashMap<String, String>();

    public void run(int z) {
        System.out.println(z+"-Running  field sample");
        long start = System.currentTimeMillis();
        for (int i = 0; i < N; i++){
            String s = Integer.toString(i);
            map.put(s,"a");
            map.remove(s);
        }
        long end = System.currentTimeMillis();
        long t = (end - start);
        fieldExecTime += t;
        System.out.println(z+"-End field sample:"+t);
    }
}

private static class ThreadLocaldExample{
    private ThreadLocal<Map<String,String>> myThreadLocal = new ThreadLocal<Map<String,String>>() {
        @Override protected Map<String, String> initialValue() {
            return new HashMap<String, String>();
        }
    };

    public void run(int z) {
        System.out.println(z+"-Running thread local sample");
        long start = System.currentTimeMillis();
        for (int i = 0; i < N; i++){
            String s = Integer.toString(i);
            myThreadLocal.get().put(s, "a");
            myThreadLocal.get().remove(s);
        }
        long end = System.currentTimeMillis();
        long t = (end - start);
        threadLocalExecTime += t;
        System.out.println(z+"-End thread local sample:"+t);
    }
}
}'

Ausgabe:

0-Lauffeldprobe

0-End Bereich Beispiel: 6044

0-Lauf lokale Thread Probe

0-End lokales Thread Beispiel: 6015

1-Lauffeldprobe

1-End-Bereich Beispiel: 5095

1-Lauf lokale Thread Probe

1-Endgewinde lokales Beispiel: 5720

2-Lauffeldprobe

2-End Bereich Beispiel: 4842

2-Lauf lokale Thread Probe

2-End lokales Thread Beispiel: 5835

3-Lauffeldprobe

3-End Bereich Beispiel: 4674

3-Lauf lokale Thread Probe

3-End lokales Thread Beispiel: 5287

4-Lauffeldprobe

4-End Bereich Beispiel: 4849

4-Lauf lokale Thread Probe

4-End lokales Thread Beispiel: 5309

5-Lauffeldprobe

5-End Bereich Beispiel: 4781

5-Lauf lokale Thread Probe

5-End lokales Thread Beispiel: 5330

6-Lauffeldprobe

6-End Bereich Beispiel: 5294

6-Lauf lokale Thread Probe

6-Endgewinde lokales Beispiel: 5511

7-Lauffeldprobe

7-End Bereich Beispiel: 5119

7-Lauf lokale Thread Probe

7-End lokales Thread Beispiel: 5793

8-Lauffeldprobe

8-End Bereich Beispiel: 4977

8-Lauf lokale Thread Probe

8-Endgewinde lokales Beispiel: 6374

9-Lauffeldprobe

9-End Bereich Beispiel: 4841

9-Lauf lokale Thread Probe

9-End lokales Thread Beispiel: 5471

Feld avg: 5051

Thread avg: 5664

Env:

openjdk Version "1.8.0_131"

Intel® Core ™ i7-7500U CPU @ 2.70GHz × 4

Ubuntu 16.04 LTS

@Pete korrekt zu testen, bevor Sie optimieren.

Ich wäre sehr überrascht, wenn ein Message einen ernsthaften Kopf hat die Konstruktion im Vergleich zu ihm actaully verwendet wird.

Miss mit Thread kann eine Quelle von Leckagen und baumelnden Referenzen sein, die keinen klaren Lebenszyklus haben, in der Regel nicht immer ich nicht Thread verwenden, ohne einen sehr klaren Plan, wann eine bestimmte Ressource entfernt wird.

Baut sie und messen.

Auch Sie brauchen nur eine Thread, wenn Sie Ihre Nachricht zu verdauen Verhalten in ein Objekt zu kapseln. Wenn Sie eine lokale Message und ein lokales byte [1000] für eine bestimmten Zweck benötigen, erstellen Sie ein Objekt mit einem Message und ein byte [] Feld und setzt das Objekt in die Thread anstatt sowohl einzeln.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top