Random ve ThreadLocalRandom Sınıflarının Performans Karşılaştırması
Java ortamında rastgele sayılar(tamsayı, kayan noktalı sayı) ve rastgele boolean
değerler üretmek için iki tip sınıf bulunuyor. Bunlar Random
ve ThreadLocalRandom
sınıflarıdır.
Random
sınıfı Java 1.0’dan beri hayatımızdayken, ThreadLocalRandom
sınıfı Java 7 sürümüyle birlikte kullanıma sunuldu. Bu iki sınıf genel manada aynı işleri yapıyor.
Örneğin;
Random random = new Random(); (1)
int i = random.nextInt(900) + 100; (2)
double d = random.nextDouble(); (3)
float f = random.nextFloat(); (4)
boolean b = random.nextBoolean(); (5)
1 | Random nesnesi oluşturuluyor. |
2 | 100 – 1000 arası rastgele tamsayı oluşturuluyor. |
3 | 0.0 – 1.0 arası rastgele 64 bitlik kayan noktalı sayı oluşturuluyor. |
4 | 0.0 – 1.0 arası rastgele 32 bitlik kayan noktalı sayı oluşturuluyor. |
5 | true veya false değer rastgele üretliyor. |
Bu işlerin benzerini Java 7 ile birlikte gelen ThreadLocalRandom
sınıfı ile de yapabiliriz.
Örneğin;
int i = ThreadLocalRandom.current().nextInt(100, 1000); (1)
double d = ThreadLocalRandom.current().nextDouble(100, 1000); (2)
float f = ThreadLocalRandom.current().nextFloat(); (3)
boolean b = ThreadLocalRandom.current().nextBoolean(); (4)
1 | 100 – 1000 arası rastgele tamsayı oluşturuluyor. |
2 | 100.0 – 1000.0 arası rastgele 64 bitlik kayan noktalı sayı oluşturuluyor. |
3 | 0.0 – 1.0 arası rastgele 32 bitlik kayan noktalı sayı oluşturuluyor. |
4 | true veya false değer rastgele üretliyor. |
Her iki sınıf da benzer işleri yapmasına ve her ikisi birden Thread-safe olmasına karşın ThreadLocalRandom
sınıfı birden fazla iş parçacığına karşı daha fazla performans sağlamaktadır.
Random
sınıfı türünden oluşturulan nesneler Thread-safe’dir fakat, artalan Thread sayısına karşı aynı anda rastgele değer üretiminde performans sıkıntıları yaşatmaktadır. İşte bu sebeple ThreadLocalRandom
sınıfı yeniden yazılmış ve artalan Thread sayısına karşı, eşzamanlı rastgele değer üretiminde daha fazla performans imkanı getirilmiştir.
Yukarıda zikrettiğim performans kazancını kanıtlamak için, sizlerle JMH (Java MicroBenchmark Harness) ile yaptığım kıyaslamayı paylaşmak isterim.
Random vs ThreadLocalRandom
JMH ile yapılan kıyaslamada, aşağıdaki niteliklere sahip Amazon EC2 makinası kullanılmıştır.
Amazon EC2 – Compute Optimized (c3.8xlarge)
OS – Ubuntu 14.04 (x64)
CPU – 32 Core
Memory – 60 Gib
Disk – 2 x 320 SSD
Java – JDK 1.8 x64
@OutputTimeUnit(TimeUnit.MILLISECONDS) (1)
@BenchmarkMode({Mode.Throughput}) (2)
public class RandomBenchmark {
private static final int START = 1; (3)
private static final int END = 2_000_000; (4)
private static final int ITERATION_COUNT = 10; (5)
private static final int WARMUP_COUNT = 10; (6)
private static final int FORK_COUNT = 3; (7)
@Benchmark
@Fork(value = FORK_COUNT)
@Warmup(iterations = WARMUP_COUNT)
@Measurement(iterations = ITERATION_COUNT)
public int classicRandom(Blackhole hole) {
int result = new Random().nextInt(END) + START;
return result;
}
@Benchmark
@Fork(value = FORK_COUNT)
@Warmup(iterations = WARMUP_COUNT)
@Measurement(iterations = ITERATION_COUNT)
public int threadLocalRandom() {
int result = ThreadLocalRandom.current().nextInt(START, END);
return result;
}
}
1 | Kıyaslama milisaniye cinsinden olacak. |
2 | Birim zamandaki operasyon sayısı hesaplanacak. |
3 | 1 ile, |
4 | 2 milyon arası sayı üretilecek. |
5 | Ölçüm 10’ar kere yapılacak. |
6 | Kızıştırma 10’ar kere yapılacak. |
7 | 3 bağımsız JVM üzerinde ölçüm tekrarlanacak. |
JMH ile yapılan bu ölçüm sonucunda aşağıdaki çıktılar elde edilmiştir.
Thread sayısı | Random (opts/ms) | ThreadLocalRandom (opts/ms) |
---|---|---|
32 |
8270.143 |
2730077.416 |
1 |
7115.396 |
157249.189 |
2 |
7205.506 |
314133.412 |
3 |
8000.412 |
470297.996 |
4 |
8275.624 |
620752.000 |
5 |
8452.557 |
782501.105 |
6 |
7873.484 |
919402.607 |
7 |
7857.637 |
1093786.369 |
8 |
7832.637 |
1243093.197 |
9 |
7455.326 |
1332173.002 |
10 |
7699.261 |
1449924.784 |
11 |
7446.810 |
1549539.416 |
12 |
7229.389 |
1647996.988 |
13 |
7048.528 |
1896487.967 |
14 |
7207.285 |
2001561.485 |
15 |
7157.251 |
2049247.241 |
16 |
6986.766 |
2063141.840 |
17 |
7244.144 |
2215793.940 |
18 |
7131.116 |
2253215.543 |
19 |
7176.455 |
2451471.446 |
20 |
7158.223 |
2451664.956 |
21 |
7021.781 |
2495864.934 |
22 |
7470.644 |
2524415.132 |
23 |
7377.497 |
2587504.613 |
24 |
7534.796 |
2606206.115 |
25 |
7112.421 |
2622841.414 |
26 |
7818.521 |
2634819.398 |
27 |
7823.749 |
2636562.658 |
28 |
7945.500 |
2652155.927 |
29 |
8159.826 |
2658746.448 |
30 |
8067.420 |
2690268.717 |
31 |
8229.543 |
2702801.516 |
opts/ms : 1 milisaniyede yapılan operasyon sayısı. (Throughput) |
Yukarıdaki tablonun grafiksel görünümü ise aşağıdaki gibidir. Sonuç gerçekten dramatik.
Benchmark uygulamasına https://github.com/rahmanusta/jmh-samples bağlantısından erişebilirsiniz.
Tekrar görüşmek dileğiyle.
Tag:backend, jmh, random, threadlocalrandom
4 Comments
Selam Rahman Hocam,
Random random = new Random(); (1)
int i = random.nextInt(1000) + 100; (2)
kısmı için 100-1000 arası demişsin ama 100-1100 arası olmayacak mı?
Saygılarımla.
Düzelttim hocam teşekkürler 🙂
merhaba hocam hazır bu konuya değinmişken şu sorum hakkında bilginiz varsa paylaşırsanız sevinirim.
http://www.btsoru.com/questions/17845/bilgisayar-genel-anlamda-random-sayy-matematiksel-olarak-nasl-olusturuyor
Bu konuda bilgim yok malesef Ahmet.