好问题,我最近一直在问自己。为了给你确定的数字,下面的基准测试(在 Scala 中,编译为与等效 Java 代码几乎相同的字节码):
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)
}
可用here,在 AMD 4x 2.8 GHz 双核和具有超线程 (2.67 GHz) 的四核 i7 上执行。
这些是数字:
i7
规格:Intel i7 2x 四核 @ 2.67 GHz
测试:scala.threads.ParallelTests
测试名称:loop_heap_read
线程数:1
总测试:200
运行时间:(显示最后 5 个)
9.0069 9.0036 9.0017 9.0084 9.0074(平均值 = 9.1034 最小值 = 8.9986 最大值 = 21.0306)
线程数:2
总测试:200
运行时间:(显示最后 5 个)
4.5563 4.7128 4.5663 4.5617 4.5724(平均 = 4.6337 最小值 = 4.5509 最大值 = 13.9476)
线程数:4
总测试:200
运行时间:(显示最后 5 个)
2.3946 2.3979 2.3934 2.3937 2.3964(平均值 = 2.5113 最小值 = 2.3884 最大值 = 13.5496)
线程数:8
总测试:200
运行时间:(显示最后 5 个)
2.4479 2.4362 2.4323 2.4472 2.4383(平均值 = 2.5562 最小值 = 2.4166 最大值 = 10.3726)
测试名称:线程本地
线程数:1
总测试:200
运行时间:(显示最后 5 个)
91.1741 90.8978 90.6181 90.6200 90.6113(平均值 = 91.0291 最小值 = 90.6000 最大值 = 129.7501)
线程数:2
总测试:200
运行时间:(显示最后 5 个)
45.3838 45.3858 45.6676 45.3772 45.3839(平均值 = 46.0555 最小值 = 45.3726 最大值 = 90.7108)
线程数:4
总测试:200
运行时间:(显示最后 5 个)
22.8118 22.8135 59.1753 22.8229 22.8172(平均 = 23.9752 最小值 = 22.7951 最大值 = 59.1753)
线程数:8
总测试:200
运行时间:(显示最后 5 个)
22.2965 22.2415 22.3438 22.3109 22.4460(平均 = 23.2676 最小值 = 22.2346 最大值 = 50.3583)
AMD
规格:AMD 8220 4x 双核 @ 2.8 GHz
测试:scala.threads.ParallelTests
测试名称:loop_heap_read
总工作量:20000000
线程数:1
总测试:200
运行时间:(显示最后 5 个)
12.625 12.631 12.634 12.632 12.628(平均值 = 12.7333 最小值 = 12.619 最大值 = 26.698)
测试名称:loop_heap_read
总工作量:20000000
运行时间:(显示最后 5 个)
6.412 6.424 6.408 6.397 6.43(平均 = 6.5367 最小值 = 6.393 最大值 = 19.716)
线程数:4
总测试:200
运行时间:(显示最后 5 个)
3.385 4.298 9.7 6.535 3.385(平均 = 5.6079 最小值 = 3.354 最大值 = 21.603)
线程数:8
总测试:200
运行时间:(显示最后 5 个)
5.389 5.795 10.818 3.823 3.824(平均 = 5.5810 最小值 = 2.405 最大值 = 19.755)
测试名称:线程本地
线程数:1
总测试:200
运行时间:(显示最后 5 个)
200.217 207.335 200.241 207.342 200.23(平均 = 202.2424 最小值 = 200.184 最大值 = 245.369)
线程数:2
总测试:200
运行时间:(显示最后 5 个)
100.208 100.199 100.211 103.781 100.215(平均 = 102.2238 最小值 = 100.192 最大值 = 129.505)
线程数:4
总测试:200
运行时间:(显示最后 5 个)
62.101 67.629 62.087 52.021 55.766(平均值 = 65.6361 最小值 = 50.282 最大值 = 167.433)
线程数:8
总测试:200
运行时间:(显示最后 5 个)
40.672 74.301 34.434 41.549 28.119(平均值 = 54.7701 最小值 = 28.119 最大值 = 94.424)
总结
本地线程大约是堆读取的 10-20 倍。在这个 JVM 实现和这些架构上,它似乎也可以很好地扩展处理器数量。