Ada*_*zyk 11 java concurrency performance caching
在马丁·汤普森的"95%的表现是关于清洁的代表性模型"谈话中,在17到21分钟之间,这样的代码被呈现:
public class Queue
{
private final Object[] buffer;
private final int capacity;
// Rest of the code
}
Run Code Online (Sandbox Code Playgroud)
在20:16他说:
你可以获得更好的性能,所以留下像这样的东西
capacity是正确的.
我试图提出一个代码示例,其capacity速度会快得多buffer.length,但我失败了.
马丁说两个场景中出现问题:
length字段也是final,JLS 10.7.所以,我不知道这可能是一个什么问题.capacityVS buffer.length一百万次(具有元素一百万队列),但没有显著差异.我使用JMH进行基准测试.能否请您提供一个代码示例,该示例演示了一个capacity优于buffer.length性能的案例?
更常见的情况(经常在实际代码中发现)越好.
请注意,我完全取消了美学,清洁代码,代码重新分解等方面的内容.我只询问性能.
正常访问数组时,JVM length仍然使用它来执行边界检查.但是当你通过sun.misc.Unsafe(像马丁那样)访问数组时,你不必支付这种隐含的惩罚.
Array的length字段通常位于与其第一个元素相同的缓存行中,因此当多个线程同时写入第一个索引时,您将具有错误共享.使用单独的字段来缓冲容量将打破这种错误共享.
这是一个基准测试,显示了capacity字段如何使数组访问速度更快:
package bench;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Threads;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
import java.util.concurrent.atomic.AtomicReferenceArray;
@State(Scope.Benchmark)
@Threads(4)
public class Queue {
private static final Unsafe unsafe = getUnsafe();
private static final long base = unsafe.arrayBaseOffset(Object[].class);
private static final int scale = unsafe.arrayIndexScale(Object[].class);
private AtomicReferenceArray<Object> atomic;
private Object[] buffer;
private int capacity;
@Param({"0", "25"})
private volatile int index;
@Setup
public void setup() {
capacity = 32;
buffer = new Object[capacity];
atomic = new AtomicReferenceArray<>(capacity);
}
@Benchmark
public void atomicArray() {
atomic.set(index, "payload");
}
@Benchmark
public void unsafeArrayLength() {
int index = this.index;
if (index < 0 || index >= buffer.length) {
throw new ArrayIndexOutOfBoundsException();
}
unsafe.putObjectVolatile(buffer, base + index * scale, "payload");
}
@Benchmark
public void unsafeCapacityField() {
int index = this.index;
if (index < 0 || index >= capacity) {
throw new ArrayIndexOutOfBoundsException();
}
unsafe.putObjectVolatile(buffer, base + index * scale, "payload");
}
private static Unsafe getUnsafe() {
try {
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
return (Unsafe) f.get(null);
} catch (IllegalAccessException | NoSuchFieldException e) {
throw new AssertionError("Should not happen");
}
}
}
Run Code Online (Sandbox Code Playgroud)
结果:
Benchmark (index) Mode Cnt Score Error Units
Queue.atomicArray 0 thrpt 5 41804,825 ± 928,882 ops/ms
Queue.atomicArray 25 thrpt 5 84713,201 ± 1067,911 ops/ms
Queue.unsafeArrayLength 0 thrpt 5 48656,296 ± 676,166 ops/ms
Queue.unsafeArrayLength 25 thrpt 5 88812,863 ± 1089,380 ops/ms
Queue.unsafeCapacityField 0 thrpt 5 88904,433 ± 360,936 ops/ms
Queue.unsafeCapacityField 25 thrpt 5 88633,490 ± 1426,329 ops/ms
Run Code Online (Sandbox Code Playgroud)