Tôi mới biết về Java 8. Tôi vẫn chưa biết sâu về API, nhưng tôi đã tạo một điểm chuẩn không chính thức nhỏ để so sánh hiệu suất của API Streams mới với các Bộ sưu tập cũ tốt.
Bài kiểm tra bao gồm lọc một danh sách Integer
và cho mỗi số chẵn, tính toán căn bậc hai và lưu trữ nó trong kết quả List
của Double
.
Đây là mã:
public static void main(String[] args) {
//Calculating square root of even numbers from 1 to N
int min = 1;
int max = 1000000;
List<Integer> sourceList = new ArrayList<>();
for (int i = min; i < max; i++) {
sourceList.add(i);
}
List<Double> result = new LinkedList<>();
//Collections approach
long t0 = System.nanoTime();
long elapsed = 0;
for (Integer i : sourceList) {
if(i % 2 == 0){
result.add(Math.sqrt(i));
}
}
elapsed = System.nanoTime() - t0;
System.out.printf("Collections: Elapsed time:\t %d ns \t(%f seconds)%n", elapsed, elapsed / Math.pow(10, 9));
//Stream approach
Stream<Integer> stream = sourceList.stream();
t0 = System.nanoTime();
result = stream.filter(i -> i%2 == 0).map(i -> Math.sqrt(i)).collect(Collectors.toList());
elapsed = System.nanoTime() - t0;
System.out.printf("Streams: Elapsed time:\t\t %d ns \t(%f seconds)%n", elapsed, elapsed / Math.pow(10, 9));
//Parallel stream approach
stream = sourceList.stream().parallel();
t0 = System.nanoTime();
result = stream.filter(i -> i%2 == 0).map(i -> Math.sqrt(i)).collect(Collectors.toList());
elapsed = System.nanoTime() - t0;
System.out.printf("Parallel streams: Elapsed time:\t %d ns \t(%f seconds)%n", elapsed, elapsed / Math.pow(10, 9));
}.
Và đây là kết quả cho một máy lõi kép:
Collections: Elapsed time: 94338247 ns (0,094338 seconds)
Streams: Elapsed time: 201112924 ns (0,201113 seconds)
Parallel streams: Elapsed time: 357243629 ns (0,357244 seconds)
Đối với thử nghiệm cụ thể này, các luồng chậm hơn khoảng hai lần so với các bộ sưu tập và song song không giúp được gì (hoặc tôi đang sử dụng sai cách?).
Câu hỏi:
- Thử nghiệm này có công bằng không? Tôi đã phạm sai lầm nào chưa?
- Là luồng chậm hơn bộ sưu tập? Có ai đã làm một tiêu chuẩn chính thức tốt về điều này?
- Cách tiếp cận nào tôi nên phấn đấu?
Cập nhật kết quả.
Tôi đã chạy thử nghiệm 1k lần sau khi khởi động JVM (lặp lại 1k) theo lời khuyên của @pveentjer:
Collections: Average time: 206884437,000000 ns (0,206884 seconds)
Streams: Average time: 98366725,000000 ns (0,098367 seconds)
Parallel streams: Average time: 167703705,000000 ns (0,167704 seconds)
Trong trường hợp này, luồng là hiệu suất cao hơn. Tôi tự hỏi những gì sẽ được quan sát trong một ứng dụng trong đó chức năng lọc chỉ được gọi một hoặc hai lần trong thời gian chạy.
toList
nên chạy song song ngay cả khi nó thu thập vào danh sách không an toàn luồng, vì các luồng khác nhau sẽ thu thập vào danh sách trung gian giới hạn luồng trước khi được hợp nhất.
IntStream
thay vào đó bạn đã thử nó chưa?