Чому друк "B" значно повільніше, ніж друк "#"?


2746

Я створив дві матриці 1000x 1000:

Перша матриця: Oі #.
Друга матриця: Oі B.

Використовуючи наступний код, на першу матрицю знадобилося 8,52 секунди:

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("");
 }

За допомогою цього коду для другої матриці знадобилося 259.152 секунди:

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("");
}

У чому причина різко різних часових пробігів?


Як запропоновано в коментарях, друк System.out.print("#");займає лише 7.8871секунди, тоді як System.out.print("B");дає still printing....

Як і інші, хто вказував, що це працює для них нормально, я, наприклад, спробував Ideone.com , і обидва фрагменти коду виконуються з однаковою швидкістю.

Умови випробувань:

  • Я провів цей тест від Netbeans 7.2 , з виходом на його консоль
  • Я використовував System.nanoTime()для вимірювань

62
Спробуйте змінити rand.nextInt (4) == 0 на i <250, щоб усунути ефект випадкового генератора. Можливо, у вас закінчиться ентропія, яка уповільнює випадкове покоління
fejese

3
Здається, обидва на моїй машині працюють приблизно однаково, ~ 4 секунди.
Сотіріос Деліманоліс

155
якщо ви припускаєте, що друк B займає більше часу, ніж друк # .... чому ви не намагаєтеся надрукувати всі B & all #, а не покладатися на випадкову змінну r
Kakarot,

18
Виходячи з прийнятої відповіді, ви, мабуть, не намагалися запустити його з результатом, переспрямованим на файл або / dev / null.
Бармар

24
@fejese, Random () не є криптографічним Rng, тому не використовує пул ентропії.
Розділіться

Відповіді:


4070

Чиста припущення полягає в тому, що ви використовуєте термінал, який намагається виконувати обертання слів, а не загортання символів, і трактує Bяк символу слова, але #як символу , який не має слова. Тож коли він доходить до кінця рядка і шукає місце, щоб перервати лінію, він бачить #майже відразу і щасливо проривається там; тоді як з допомогою B, він повинен тримати пошук довше, і може мати більше тексту для завершення (що може бути дорогим на деяких терміналах, наприклад, виведення зворотних просторів, а потім виведення пробілів, щоб перезаписати загортані літери).

Але це чисті спекуляції.


559
Це насправді правильна відповідь! Додавання пробілу після Bвирішення його.
Kuba Spatny

261
Є кілька відповідей, які випливають із важкого досвіду. TJ і я (оскільки ми друзі) виросли в часи Apple] [і zx80 / ​​81. Тоді не було вбудованого загортання слів. Тож ми обоє закінчили писати своє - не раз. І ці уроки дотримуються вас, вони спалюються до вашого мозку ящірки. Але якщо ви схилилися до коду після цього, коли ваше середовище слово завершує все, або ви робите це вручну перед початком виконання, складніше зіткнутися з проблемами з обгортанням слів.
JockM

315
Блискуча дедукція. Але ми повинні узагальнювати цей урок і завжди вимірювати продуктивність з вилученим, направленим на / dev / null (NUL в Windows) або принаймні на файл. Відображення на будь-якій консолі, як правило, дуже дорогий IO, і завжди спотворює таймінги - навіть якщо не настільки заплутано, як це.
Боб Кернс

37
@MrLister: System.out.printlnне робить перетягування слів; річ, на яку вона виводила, робила обговорення слів (і блокувала, тому System.out.printlnдовелося чекати).
TJ Crowder

35
@Chris - власне, я стверджую, що не друк їх - це рішення, щоб отримати точні терміни алгоритму. Кожен раз, коли ви друкуєте на консолі (будь-якого виду), ви викликаєте всі способи зовнішньої обробки, не пов’язані з тим, на що ви тестуєте продуктивність. Це помилка у вашій процедурі вимірювання, чисто і просто. З іншого боку, якщо ви розглядаєте проблему не як вимірювання, а розуміння невідповідності, то так, не друк - це хитрість налагодження. Це зводиться до того, яку проблему ви намагаєтеся вирішити?
Боб Кернс

209

Я провів тести на Eclipse vs Netbeans 8.0.2, обидва з версією Java 1.8; Я використовував System.nanoTime()для вимірювань.

Затемнення:

Я отримав однаковий час в обох випадках - близько 1,564 секунди .

Netbeans:

  • Використання "#": 1,536 секунди
  • Використання "B": 44,164 секунди

Отже, схоже, що Netbeans має погану ефективність при друкуванні до консолі.

Після додаткових досліджень я зрозумів, що проблема полягає в обшивці рядків максимуму буфера Netbeans (це не обмежується System.out.printlnкомандами), продемонстрованого цим кодом:

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("");
}

Результати часу становлять менше 1 мілісекунди за кожну ітерацію, за винятком кожної п’ятої ітерації , коли результат часу становить близько 225 мілісекунд. Щось на зразок (у наносекундах):

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

І так далі..

Підсумок:

  1. Eclipse прекрасно працює з "B"
  2. У Netbeans є проблема обертання рядків, яку можна вирішити (оскільки проблема не виникає в затемненні) (без додавання пробілу після B ("B")).

32
чи можете ви детальніше розглянути свої стратегії дослідження, а потім, що остаточно змусило вас з’ясувати, що винуватцем лінії є перенесення (Мені цікаво ваших детективних навичок, тобто!)
silph

12

Так, винуватець, безумовно, словозламний. Коли я тестував ваші дві програми, NetBeans IDE 8.2 дав мені наступний результат.

  1. Перша матриця: O і # = 6,03 секунди
  2. Друга матриця: O і B = 50,97 секунди

Придивившись уважно до свого коду, ви використали перерву рядка в кінці першого циклу. Але ви не використовували жодного розриву рядків у другому циклі. Отже, ви збираєтесь надрукувати слово з 1000 символів у другому циклі. Це спричиняє словозахисну проблему. Якщо ми використовуємо не слова "" після B, то для складання програми потрібно всього 5,35 секунд . І якщо ми використаємо розрив рядка у другому циклі після проходження 100 значень або 50 значень, це займає лише 8,56 секунди та 7,05 секунди відповідно.

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("");                
}

Ще одна порада - це змінити настройки NetBeans IDE. Перш за все, перейдіть до інструментів NetBeans та натисніть Опції . Після цього натисніть Редактор та перейдіть на вкладку Форматування . Потім виберіть " Anywhere" у варіанті обертання рядків . Для складання програми знадобиться майже 6,24% менше часу.

Налаштування редактора NetBeans

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.