Về hiệu suất, skipList
khi được sử dụng làm Bản đồ - có vẻ chậm hơn 10-20 lần. Dưới đây là kết quả của các xét nghiệm của tôi (Java 1.8.0_102-b14, giành chiến thắng x32)
Benchmark Mode Cnt Score Error Units
MyBenchmark.hasMap_get avgt 5 0.015 ? 0.001 s/op
MyBenchmark.hashMap_put avgt 5 0.029 ? 0.004 s/op
MyBenchmark.skipListMap_get avgt 5 0.312 ? 0.014 s/op
MyBenchmark.skipList_put avgt 5 0.351 ? 0.007 s/op
Và thêm vào đó - sử dụng hợp cụ thể mà so sánh một-một thực sự có ý nghĩa. Triển khai bộ nhớ cache của các mục gần đây nhất được sử dụng bằng cả hai bộ sưu tập này. Bây giờ hiệu quả của skipList dường như là sự kiện đáng ngờ hơn.
MyBenchmark.hashMap_put1000_lru avgt 5 0.032 ? 0.001 s/op
MyBenchmark.skipListMap_put1000_lru avgt 5 3.332 ? 0.124 s/op
Đây là mã cho JMH (thực hiện như java -jar target/benchmarks.jar -bm avgt -f 1 -wi 5 -i 5 -t 1
)
static final int nCycles = 50000;
static final int nRep = 10;
static final int dataSize = nCycles/4;
static final List<String> data = new ArrayList<>(nCycles);
static final Map<String,String> hmap4get = new ConcurrentHashMap<>(3000, 0.5f, 10);
static final Map<String,String> smap4get = new ConcurrentSkipListMap<>();
static {
// prepare data
List<String> values = new ArrayList<>(dataSize);
for(int i = 0; i < dataSize; i++) {
values.add(UUID.randomUUID().toString());
}
// rehash data for all cycles
for(int i = 0; i < nCycles; i++) {
data.add(values.get((int)(Math.random() * dataSize)));
}
// rehash data for all cycles
for(int i = 0; i < dataSize; i++) {
String value = data.get((int)(Math.random() * dataSize));
hmap4get.put(value, value);
smap4get.put(value, value);
}
}
@Benchmark
public void skipList_put() {
for(int n = 0; n < nRep; n++) {
Map<String,String> map = new ConcurrentSkipListMap<>();
for(int i = 0; i < nCycles; i++) {
String key = data.get(i);
map.put(key, key);
}
}
}
@Benchmark
public void skipListMap_get() {
for(int n = 0; n < nRep; n++) {
for(int i = 0; i < nCycles; i++) {
String key = data.get(i);
smap4get.get(key);
}
}
}
@Benchmark
public void hashMap_put() {
for(int n = 0; n < nRep; n++) {
Map<String,String> map = new ConcurrentHashMap<>(3000, 0.5f, 10);
for(int i = 0; i < nCycles; i++) {
String key = data.get(i);
map.put(key, key);
}
}
}
@Benchmark
public void hasMap_get() {
for(int n = 0; n < nRep; n++) {
for(int i = 0; i < nCycles; i++) {
String key = data.get(i);
hmap4get.get(key);
}
}
}
@Benchmark
public void skipListMap_put1000_lru() {
int sizeLimit = 1000;
for(int n = 0; n < nRep; n++) {
ConcurrentSkipListMap<String,String> map = new ConcurrentSkipListMap<>();
for(int i = 0; i < nCycles; i++) {
String key = data.get(i);
String oldValue = map.put(key, key);
if((oldValue == null) && map.size() > sizeLimit) {
// not real lru, but i care only about performance here
map.remove(map.firstKey());
}
}
}
}
@Benchmark
public void hashMap_put1000_lru() {
int sizeLimit = 1000;
Queue<String> lru = new ArrayBlockingQueue<>(sizeLimit + 50);
for(int n = 0; n < nRep; n++) {
Map<String,String> map = new ConcurrentHashMap<>(3000, 0.5f, 10);
lru.clear();
for(int i = 0; i < nCycles; i++) {
String key = data.get(i);
String oldValue = map.put(key, key);
if((oldValue == null) && lru.size() > sizeLimit) {
map.remove(lru.poll());
lru.add(key);
}
}
}
}
Nguồn
2016-09-15 08:53:04
Ok. Log (n) là tốt nhưng ConcurrentSkipListMap là không gian hiệu quả? – DKSRathore
Danh sách bỏ qua cần thiết lớn hơn Hashtables, nhưng bản chất có thể điều chỉnh của ConcurrentHashMap giúp bạn có thể xây dựng một Hashtable lớn hơn ConcurrentSkipListMap tương đương. Nói chung, tôi mong đợi danh sách bỏ qua sẽ lớn hơn nhưng theo cùng thứ tự độ lớn. –
"Nó cũng không hỗ trợ điều chỉnh vì mục đích đồng thời" .. Tại sao? Liên kết là gì? – Pacerier