Tại sao việc in ấn B BẠCH chậm hơn đáng kể so với in ấn # #?


2746

Tôi đã tạo hai ma trận của 1000x 1000:

Ma trận đầu tiên: O#.
Ma trận thứ hai: OB.

Sử dụng mã sau đây, ma trận đầu tiên mất 8,52 giây để hoàn thành:

Random r = new Random();
for (int i = 0; i < 1000; i++) {
    for (int j = 0; j < 1000; j++) {
        if(r.nextInt(4) == 0) {
            System.out.print("O");
        } else {
            System.out.print("#");
        }
    }

   System.out.println("");
 }

Với mã này, ma trận thứ hai mất 259.152 giây để hoàn thành:

Random r = new Random();
for (int i = 0; i < 1000; i++) {
    for (int j = 0; j < 1000; j++) {
        if(r.nextInt(4) == 0) {
            System.out.print("O");
        } else {
            System.out.print("B"); //only line changed
        }
    }

    System.out.println("");
}

Lý do đằng sau thời gian chạy khác nhau đáng kể là gì?


Như được đề xuất trong các ý kiến, in chỉ System.out.print("#");mất 7.8871vài giây, trong khi System.out.print("B");cho still printing....

Như những người khác chỉ ra rằng nó hoạt động bình thường với họ, tôi đã thử Ideone.com và cả hai đoạn mã đều thực thi ở cùng một tốc độ.

Điều kiện kiểm tra:

  • Tôi đã chạy thử nghiệm này từ Netbeans 7.2 , với đầu ra vào bảng điều khiển của nó
  • Tôi dùng System.nanoTime()để đo

62
Hãy thử thay đổi rand.nextInt (4) == 0 thành i <250 để loại bỏ ảnh hưởng của trình tạo ngẫu nhiên. Bạn có thể hết entropy làm chậm thế hệ ngẫu nhiên
fejese

3
Cả hai dường như chạy trong cùng một khoảng thời gian trên máy của tôi, ~ 4 giây.
Sotirios Delimanolis

155
nếu bạn đề xuất rằng in B mất nhiều thời gian hơn in # .... tại sao bạn không thử in tất cả B & all # thay vì dựa vào biến ngẫu nhiên r
Kakarot

18
Dựa trên câu trả lời được chấp nhận, rõ ràng bạn đã không thử chạy nó với đầu ra được chuyển hướng đến một tệp hoặc / dev / null.
Barmar

24
@fejese, Random () không phải là một loại tiền mã hóa và do đó không sử dụng hết nhóm entropy.
Chia

Câu trả lời:


4070

Suy đoán thuần túy là bạn đang sử dụng một thiết bị đầu cuối cố gắng thực hiện gói từ thay vì gói ký tự và coi Bnhư một ký tự từ nhưng #là một ký tự không phải từ. Vì vậy, khi nó đến cuối của một dòng và tìm kiếm một nơi để phá vỡ dòng, nó thấy một sự #phá vỡ gần như ngay lập tức và hạnh phúc ở đó; trong khi đó B, nó phải tiếp tục tìm kiếm lâu hơn và có thể có nhiều văn bản hơn để bọc (có thể tốn kém trên một số thiết bị đầu cuối, ví dụ, xuất ra các khoảng trống, sau đó xuất ra khoảng trắng để ghi đè lên các chữ cái được bọc).

Nhưng đó là suy đoán thuần túy.


560
Đây thực sự là câu trả lời chính xác! Thêm một không gian sau khi Bgiải quyết nó.
Kuba Spatny

261
Có một số câu trả lời đến từ kinh nghiệm khó học. TJ và tôi (vì chúng tôi là bạn bè) lớn lên trong thời của Apple] [và zx80 / ​​81. Không có xây dựng trong bọc từ sau đó. Vì vậy, cả hai chúng tôi đã kết thúc việc viết riêng của chúng tôi - hơn một lần. Và những bài học gắn bó với bạn, chúng bị đốt cháy trong não thằn lằn của bạn. Nhưng nếu bạn nghiêng về mã sau đó, khi từ môi trường của bạn kết thúc mọi thứ hoặc bạn thực hiện thủ công trước khi chạy, thì việc chạy vào các vấn đề với gói từ sẽ khó khăn hơn.
JockM

315
Rực rỡ khấu trừ. Nhưng chúng ta nên khái quát từ bài học này và luôn đo lường hiệu suất với đầu ra bị loại bỏ, hướng đến / dev / null (NUL trên Windows) hoặc ít nhất là vào một tệp. Hiển thị trên bất kỳ loại Bảng điều khiển nào thường rất đắt IO và luôn làm biến dạng thời gian - ngay cả khi không gây nhầm lẫn đáng kể như thế này.
Bob Kerns

37
@MrLister: System.out.printlnkhông thực hiện wordwrapping; điều nó được đưa ra là thực hiện gói từ (và chặn, vì vậy System.out.printlnphải chờ).
TJ Crowder

35
@Chris - Thật ra, tôi sẽ lập luận rằng việc không in chúng là giải pháp, cho vấn đề lấy thời gian chính xác của thuật toán. Mỗi lần bạn in ra Bảng điều khiển (dưới bất kỳ hình thức nào), bạn sẽ gọi tất cả các cách xử lý bên ngoài không liên quan đến những gì bạn đang kiểm tra hiệu suất. Đó là một lỗi trong quy trình đo lường của bạn, thuần túy và đơn giản. Mặt khác, nếu bạn xem vấn đề không phải là đo lường, nhưng hiểu sự khác biệt, thì có, không in là một mẹo gỡ lỗi. Nó đi xuống, vấn đề mà bạn đang cố gắng giải quyết?
Bob Kerns

209

Tôi đã thực hiện các thử nghiệm trên Eclipse vs Netbeans 8.0.2, cả hai đều có phiên bản Java 1.8; Tôi đã sử dụng System.nanoTime()để đo lường.

Nhật thực:

Tôi có cùng thời gian trên cả hai trường hợp - khoảng 1,564 giây .

Netbeans:

  • Sử dụng "#": 1,536 giây
  • Sử dụng "B": 44.164 giây

Vì vậy, có vẻ như Netbeans có hiệu suất kém khi in lên bàn điều khiển.

Sau khi nghiên cứu thêm, tôi nhận ra rằng vấn đề là gói dòng bộ đệm tối đa của Netbeans (nó không bị hạn chế đối với System.out.printlnlệnh), được thể hiện bằng mã này:

for (int i = 0; i < 1000; i++) {
    long t1 = System.nanoTime();
    System.out.print("BBB......BBB"); \\<-contain 1000 "B"
    long t2 = System.nanoTime();
    System.out.println(t2-t1);
    System.out.println("");
}

Kết quả thời gian ít hơn 1 mili giây mỗi lần lặp trừ mỗi lần lặp thứ năm , khi kết quả thời gian là khoảng 225 mili giây. Một cái gì đó như (tính bằng nano giây):

BBB...31744
BBB...31744
BBB...31744
BBB...31744
BBB...226365807
BBB...31744
BBB...31744
BBB...31744
BBB...31744
BBB...226365807
.
.
.

Và như thế..

Tóm lược:

  1. Eclipse hoạt động hoàn hảo với "B"
  2. Netbeans có một vấn đề bao bọc dòng có thể được giải quyết (vì vấn đề không xảy ra trong nhật thực) (không thêm không gian sau B ("B")).

32
bạn có thể giải thích về các chiến lược nghiên cứu của mình và sau đó điều gì cuối cùng đã khiến bạn phát hiện ra rằng việc gói hàng là thủ phạm? (tôi tò mò về kỹ năng thám tử của bạn, nghĩa là vậy!)
silph

12

Vâng, thủ phạm chắc chắn là gói từ. Khi tôi thử nghiệm hai chương trình của bạn, NetBeans IDE 8.2 đã cho tôi kết quả như sau.

  1. Ma trận đầu tiên: O và # = 6.03 giây
  2. Ma trận thứ hai: O và B = 50,97 giây

Nhìn kỹ mã của bạn, bạn đã sử dụng ngắt dòng ở cuối vòng lặp đầu tiên. Nhưng bạn đã không sử dụng bất kỳ ngắt dòng trong vòng lặp thứ hai. Vì vậy, bạn sẽ in một từ có 1000 ký tự trong vòng lặp thứ hai. Điều đó gây ra một vấn đề gói từ. Nếu chúng ta sử dụng ký tự không phải từ "" sau B, chỉ mất 5,35 giây để biên dịch chương trình. Và nếu chúng ta sử dụng ngắt dòng trong vòng lặp thứ hai sau khi chuyển 100 giá trị hoặc 50 giá trị, thì chỉ mất 8,56 giây7,05 giây .

Random r = new Random();
for (int i = 0; i < 1000; i++) {
    for (int j = 0; j < 1000; j++) {
        if(r.nextInt(4) == 0) {
            System.out.print("O");
        } else {
            System.out.print("B");
        }
        if(j%100==0){               //Adding a line break in second loop      
            System.out.println();
        }                    
    }
    System.out.println("");                
}

Một lời khuyên khác là thay đổi cài đặt của NetBeans IDE. Trước hết, hãy truy cập NetBeans Tools và nhấp vào Tùy chọn . Sau đó bấm vào Trình chỉnh sửa và chuyển đến tab Định dạng . Sau đó chọn Anywhere trong Line Wrap Option. Sẽ mất ít hơn 6,24% thời gian để biên dịch chương trình.

Cài đặt trình chỉnh sửa NetBeans

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.