Chương trình kèm theo (xem ở cuối), khi thực hiện, mang lại kết quả như sau:Tại sao ngủ giữa lặp gây ra hoạt động trong vòng một để mất nhiều thời gian hơn so với trường hợp nó không ngủ
..........
with sleep time of 0ms
times= [1, 1, 1, 0, 1, 1, 0, 1, 1, 0]
average= 0.7
..........
with sleep time of 2000ms
times= [2, 2, 2, 2, 2, 1, 2, 2, 2, 2]
average= 1.9
Trong cả hai trường hợp chính xác cùng một mã được thực hiện mà là để liên tục có được giá trị tiếp theo từ một đối tượng ngẫu nhiên được khởi tạo ở đầu chương trình. Phương pháp khởi động được thực hiện trước tiên được cho là kích hoạt bất kỳ loại phân loại JIT nào trước khi thử nghiệm thực tế bắt đầu.
Có ai giải thích lý do cho sự khác biệt này không? Tôi đã có thể lặp lại kết quả này trong máy tính của tôi mỗi lần cho đến nay, và điều này đã được thực hiện trên một hệ thống Windows đa lõi với java 7.
Một điều thú vị là nếu thứ tự các thử nghiệm được thực hiện là đảo ngược, có nghĩa là, nếu chúng ta chạy vòng lặp với độ trễ trước khi vòng lặp mà không có sự chậm trễ, thì timings tương tự hơn (với không có vòng lặp chậm trễ thực sự mất nhiều thời gian):
..........
with sleep time of 2000ms
times= [2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
average= 2.0
..........
with sleep time of 0ms
times= [2, 3, 3, 2, 3, 3, 2, 3, 2, 3]
average= 2.6
như nhiều như tôi có thể nói , không có đối tượng nào đang được tạo bên trong phương thức hoạt động, và khi chạy điều này thông qua một trình lược tả thì dường như không có bộ sưu tập rác nào được kích hoạt. Một phỏng đoán hoang dã là một số giá trị được lưu trữ trong bộ nhớ cache cục bộ bộ xử lý bị xóa khi luồng được đặt vào chế độ ngủ và sau đó khi luồng đánh thức nó cần lấy giá trị từ bộ nhớ chính, nhưng điều đó không quá nhanh. Tuy nhiên, điều đó không giải thích tại sao đảo ngược thứ tự tạo ra sự khác biệt ...
Tình huống thực tế khi tôi bắt đầu quan sát hành vi này (nhắc tôi viết lớp thử nghiệm mẫu này) là XML unmarshalling, nơi tôi nhận thấy rằng unmarshalling cùng một tài liệu lặp đi lặp lại lần sau cái kia nhanh chóng mang lại thời gian tốt hơn so với thực hiện cùng một điều nhưng với một sự chậm trễ giữa các cuộc gọi đến unmarshal (chậm trễ tạo ra thông qua giấc ngủ hoặc bằng tay).
Đây là mã:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Tester
{
public static void main(String[] args) throws InterruptedException
{
warmUp(10000);
int numRepetitions = 10;
runOperationInALoop(numRepetitions, 0);
runOperationInALoop(numRepetitions, 2000);
}
private static void runOperationInALoop(int numRepetitions, int sleepTime) throws InterruptedException
{
List<Long> times = new ArrayList<Long>(numRepetitions);
long totalDuration = 0;
for(int i=0; i<numRepetitions; i++)
{
Thread.sleep(sleepTime);
long before = System.currentTimeMillis();
someOperation();
long duration = System.currentTimeMillis() - before;
times.add(duration);
totalDuration = totalDuration + duration;
System.out.print(".");
}
System.out.println();
double averageTimePerOperation = totalDuration/(double)numRepetitions;
System.out.println("with sleep time of " + sleepTime + "ms");
System.out.println(" times= " + times);
System.out.println(" average= " + averageTimePerOperation);
}
private static void warmUp(int warmUpRepetitions)
{
for(int i=0; i<warmUpRepetitions; i++)
{
someOperation();
}
}
public static int someInt;
public static Random random = new Random(123456789L);
private static void someOperation()
{
for(int j=0; j<50000; j++)
{
someInt = ((int)random.nextInt()*10) + 1;
}
}
}
Điều đó có ý nghĩa và tôi cho rằng phỏng đoán hoang dã của tôi không phải là quá tuyệt đối. Tuy nhiên, vẫn chưa rõ lý do tại sao phiên bản "không ngủ" của vòng lặp cho thấy hiệu suất tương tự (tồi tệ hơn) khi nó được thực hiện sau phiên bản "có ngủ". Cảm ơn các liên kết! – jsiqueira
"Cách duy nhất để tránh bỏ lõi là chờ đợi bận rộn" - một chủ đề đang chờ đợi bận rộn vẫn có thể được sắp xếp trước theo lịch trình, phải không? Điều đó vẫn sẽ gây ra bối cảnh chuyển đổi và bộ nhớ cache thay đổi bộ xử lý, như tôi hiểu nó. Cần điều tra thêm về cách hoạt động của tính năng gắn kết chuỗi chủ đề. – jsiqueira
Trên Linux, bạn có thể báo cho bộ lập lịch để tách riêng các CPU cụ thể. Nếu bạn sử dụng ái lực luồng để chỉ định một luồng cho một CPU bị cô lập, nó sẽ không bị làm trống bởi một luồng khác. –