Nói về hiệu suất:
TL; DR
Sử dụng isInstance hoặc instanceof có hiệu suất tương tự. isAssignableFrom chậm hơn một chút.
Sắp xếp theo hiệu suất:
- isstance
- ví dụ (+ 0,5%)
- isAssignableFrom (+ 2,7%)
Dựa trên điểm chuẩn 2000 lần lặp trên JAVA 8 Windows x64, với 20 lần lặp khởi động.
Về lý thuyết
Sử dụng trình xem mềm như mã byte, chúng ta có thể dịch từng toán tử thành mã byte.
Trong ngữ cảnh của:
package foo;
public class Benchmark
{
public static final Object a = new A();
public static final Object b = new B();
...
}
JAVA:
b instanceof A;
Mã byte:
getstatic foo/Benchmark.b:java.lang.Object
instanceof foo/A
JAVA:
A.class.isInstance(b);
Mã byte:
ldc Lfoo/A; (org.objectweb.asm.Type)
getstatic foo/Benchmark.b:java.lang.Object
invokevirtual java/lang/Class isInstance((Ljava/lang/Object;)Z);
JAVA:
A.class.isAssignableFrom(b.getClass());
Mã byte:
ldc Lfoo/A; (org.objectweb.asm.Type)
getstatic foo/Benchmark.b:java.lang.Object
invokevirtual java/lang/Object getClass(()Ljava/lang/Class;);
invokevirtual java/lang/Class isAssignableFrom((Ljava/lang/Class;)Z);
Đo lường có bao nhiêu hướng dẫn mã byte được sử dụng bởi mỗi toán tử, chúng ta có thể mong đợi instanceof và isInstance nhanh hơn isAssignableFrom . Tuy nhiên, hiệu suất thực tế KHÔNG được xác định bởi mã byte mà bởi mã máy (phụ thuộc vào nền tảng). Chúng ta hãy làm một điểm chuẩn vi mô cho mỗi toán tử.
Điểm chính xác
Tín dụng: Theo lời khuyên của @ aleksandr-dubinsky và cảm ơn @yura đã cung cấp mã cơ sở, đây là điểm chuẩn JMH (xem hướng dẫn điều chỉnh này ):
class A {}
class B extends A {}
public class Benchmark {
public static final Object a = new A();
public static final Object b = new B();
@Benchmark
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public boolean testInstanceOf()
{
return b instanceof A;
}
@Benchmark
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public boolean testIsInstance()
{
return A.class.isInstance(b);
}
@Benchmark
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public boolean testIsAssignableFrom()
{
return A.class.isAssignableFrom(b.getClass());
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(TestPerf2.class.getSimpleName())
.warmupIterations(20)
.measurementIterations(2000)
.forks(1)
.build();
new Runner(opt).run();
}
}
Đã cho các kết quả sau (điểm là một số thao tác trong một đơn vị thời gian , do đó điểm càng cao càng tốt):
Benchmark Mode Cnt Score Error Units
Benchmark.testIsInstance thrpt 2000 373,061 ± 0,115 ops/us
Benchmark.testInstanceOf thrpt 2000 371,047 ± 0,131 ops/us
Benchmark.testIsAssignableFrom thrpt 2000 363,648 ± 0,289 ops/us
Cảnh báo
- điểm chuẩn là JVM và nền tảng phụ thuộc. Do không có sự khác biệt đáng kể giữa mỗi hoạt động, nên có thể nhận được một kết quả khác nhau (và có thể là thứ tự khác nhau!) Trên một phiên bản JAVA và / hoặc các nền tảng khác nhau như Solaris, Mac hoặc Linux.
- điểm chuẩn so sánh hiệu suất của "là B là một thể hiện của A" khi "B mở rộng A" trực tiếp. Nếu hệ thống phân cấp lớp sâu hơn và phức tạp hơn (như B mở rộng X kéo dài Y kéo dài Z kéo dài A), kết quả có thể khác.
- Thông thường nên viết mã trước tiên chọn một trong các toán tử (thuận tiện nhất) và sau đó cấu hình mã của bạn để kiểm tra xem có tắc nghẽn hiệu suất không. Có thể toán tử này không đáng kể trong ngữ cảnh mã của bạn hoặc có thể ...
- liên quan đến điểm trước đó,
instanceof
trong bối cảnh mã của bạn có thể được tối ưu hóa dễ dàng hơn so isInstance
với ví dụ ...
Để cho bạn một ví dụ, lấy vòng lặp sau:
class A{}
class B extends A{}
A b = new B();
boolean execute(){
return A.class.isAssignableFrom(b.getClass());
// return A.class.isInstance(b);
// return b instanceof A;
}
// Warmup the code
for (int i = 0; i < 100; ++i)
execute();
// Time it
int count = 100000;
final long start = System.nanoTime();
for(int i=0; i<count; i++){
execute();
}
final long elapsed = System.nanoTime() - start;
Nhờ có JIT, mã được tối ưu hóa tại một số điểm và chúng tôi nhận được:
- instanceof: 6ms
- isstance: 12ms
- isAssignableFrom: 15ms
Ghi chú
Ban đầu bài đăng này đang thực hiện điểm chuẩn của riêng mình bằng cách sử dụng vòng lặp for trong JAVA thô, điều này cho kết quả không đáng tin cậy vì một số tối ưu hóa như Just In Time có thể loại bỏ vòng lặp. Vì vậy, chủ yếu là đo trình biên dịch JIT mất bao lâu để tối ưu hóa vòng lặp: xem Kiểm tra hiệu suất độc lập với số lần lặp để biết thêm chi tiết
Câu hỏi liên quan