Проблемы с Java - ArrayList и функция истекшего времени - PullRequest
2 голосов
/ 08 сентября 2010

Я пытаюсь создать 5 списков ArrayList различного размера, заполнить их случайными числами от 0 до 1, а затем определить время (и вывести на печать) время, необходимое для итерации каждого из них.

Мне кажется, яправильно инициализировал и заполнил их.Но когда я перебираю и проверяю время, цифры выключаются.Я получаю что-то вроде (0, 0, 2, 0, 0 секунд), когда они должны увеличиваться.

Вот код, есть идеи?

    import java.util.*;    // Imports all java.util subclasses.
public class Lab2 {

  public static void main (String[] args)
  {
    System.out.println("#2");

    int size1 = 100;
    int size2 = 1000;
    int size3 = 10000;
    int size4 = 100000;
    int size5 = 1000000;

    // ArrayList 100.
    ArrayList<Double> arrList1 = new ArrayList<Double>();
    for (int i = 0; i < size1; i++)
    {
        arrList1.add(Math.random());
    }

    long startTime11 = System.currentTimeMillis();
    for (int i = 0; i < arrList1.size(); i++);
    long total11 = System.currentTimeMillis() - startTime11;
    System.out.println("arrList1 Elapsed Time:" + total11);

    // ArrayList 1000.
    ArrayList<Double> arrList2 = new ArrayList<Double>();
    for (int i = 0; i < size2; i++)
    {
        arrList2.add(Math.random());
    }
    long startTime12 = System.currentTimeMillis();
    for (int i = 0; i < arrList2.size(); i++);
    long total12 = System.currentTimeMillis() - startTime12;
    System.out.println("arrList2 Elapsed Time:" + total12);

    // ArrayList 10000.
    ArrayList<Double> arrList3 = new ArrayList<Double>();
    for (int i = 0; i < size3; i++)
    {
        arrList3.add(Math.random());
    }

    long startTime13 = System.currentTimeMillis();
    for (int i = 0; i < arrList3.size(); i++);
    long total13 = System.currentTimeMillis() - startTime13;
    System.out.println("arrList3 Elapsed Time:" + total13);

    // ArrayList 100000.
    ArrayList<Double> arrList4 = new ArrayList<Double>();
    for (int i = 0; i < size4; i++)
    {
        arrList4.add(Math.random());
    }

    long startTime14 = System.currentTimeMillis();
    for (int i = 0; i < arrList4.size(); i++);
    long total14 = System.currentTimeMillis() - startTime14;
    System.out.println("arrList4 Elapsed Time:" + total14);

    // ArrayList 1000000.
    ArrayList<Double> arrList5 = new ArrayList<Double>();
    for (int i = 0; i < size5; i++)
    {
        arrList5.add(Math.random());
    }

    long startTime15 = System.currentTimeMillis();
    for (int i = 0; i < arrList5.size(); i++);
    long total15 = System.currentTimeMillis() - startTime15;
    System.out.println("arrList5 Elapsed Time:" + total15);

Ответы [ 7 ]

3 голосов
/ 08 сентября 2010

Не знаю, почему некоторые из них завершаются раньше других, если только это не связано с кэшированием чисел в JVM, но я могу сказать, что использование nanoTime даст лучшие показатели.http://ideone.com/ktCXP

3 голосов
/ 08 сентября 2010

Так как это домашнее задание, вот несколько советов о том, что вы должны принять во внимание при написании микро-тестов Java (например, так):

1 - Компиляторы Java умны. Если они выяснят, что какая-то часть вашего кода не влияет на видимые результаты этого кода, они их оптимизируют.

Чтобы это не исказило результаты тестов, вам, как правило, необходимо убедиться, что ваши циклы тестов влияют на результат программы. Например, пусть они сделают какой-нибудь дешевый расчет, способствующий получению результата, и распечатают его в конце контрольной отметки.

2 - JVM требуется время для «разогрева». Когда вы запускаете приложение в типичной Sun JVM (и других), ваш код первоначально интерпретируется интерпретатором байт-кода. Через некоторое время JVM решает, что стоит JIT компилировать ваш код в собственный код ... и тот, который произошел, ваш код начинает работать намного быстрее. (Но во время компиляции JIT может показаться, что он работает очень медленно.)

Чтобы это не исказило результаты теста, вам обычно нужно организовать, чтобы ваши циклы (фактически весь тест) запускались несколько раз. Обычно я делаю весь тестовый метод методом и запускаю его несколько раз в цикле. Затем я смотрю на цифры, чтобы увидеть точку их стабилизации, и обращаю внимание только на цифры после этой точки.

3 - Тесты, которые включают повторное создание объектов / массивов, имеют тенденцию запускать сборку мусора в «случайных» точках. Если ГХ работает (в зависимости от настроек ГХ) в середине цикла тестирования, время, необходимое для запуска этого цикла, может быть завышено. В зависимости от того, что вы пытаетесь измерить, это может дать вам аномальные результаты.

Если вы пытаетесь исключить накладные расходы на сборку мусора, вы можете установить начальный размер кучи JVM на очень большое число, чтобы GC никогда не запускался. Кроме того, вы можете вручную удалить аномальные результаты на глаз или сопоставив результаты прогонов ГХ, указанные в файле журнала ГХ.

OTOH, если вы хотите включить издержки GC, использовать типичный размер кучи, запускать циклы большое количество времени и вычислять среднее время для цикла.

3 голосов
/ 08 сентября 2010

Вы ничего не делаете в своих циклах, поэтому они, вероятно, оптимизируются компилятором и не выполняются вообще.

2 голосов
/ 08 сентября 2010

Да, ваши циклы оптимизируются - будьте осторожны, Java умна и может даже оптимизировать такие вещи, как:

{
    int a;
    for(int b=0;b<10000;b++)
        a++;
}

, потому что она может знать, что вы никогда не используете значение в!

Также, пожалуйста, измените первую часть вашей программы на:

int[] sizes = new int[] {100,1000,10000,100000,1000000};

и затем используйте в своем коде:

for(int size:sizes) {
    ArrayList<Double> arrList = new ArrayList<Double>();
    for (int i = 0; i < size; i++)
    {
        arrList.add(Math.random());
    }
    long startTime = System.currentTimeMillis();

    double sum=0;

    for (int i = 0; i < arrList.size(); i++)
        sum=sum+arrList.get(i); // may need casting here

    long total = System.currentTimeMillis() - startTime;
    System.out.println("Loop for size:"+size+"  Elapsed Time:" + total);
}

Способ, которым вы копировали, вставляли и редактировалився эта чушь ранит меня повсюду.Это так неправильно, даже делать это один раз - даже в качестве первого прохода.

Если вы когда-либо копируете и вставляете, когда кодируете, есть 95% вероятность, что вы делаете это неправильно.Если у вас когда-либо есть переменные с именами в конце, вы почти наверняка делаете это неправильно.Если вы обнаружите, что редактируете по какому-то шаблону, например, изменяете 1 на 2 в конце переменной в наборах кода, которые выглядят одинаково, то вы абсолютно уверены, что делаете это неправильно.

Вы увидите это, когда попытаетесь исправить код, который вы написали, вместо того, чтобы делать это так, как я указал выше.

--- Другое редактирование --- Изменено, чтобы оно могло что-то делать с результирующим значением--в этом случае он суммирует их, проходя по нему.Извините за ранее, я слишком быстро просматриваю вещи, но это должно, по крайней мере, что-то случиться.

1 голос
/ 08 сентября 2010

U должен

  1. Напишите метод для итерации. Этот метод может принимать размер в качестве параметра. Создайте правильный размер списка и время его итерации. Как Билл К Сез копировать / вставлять плохо, методы хорошие.
  2. Измерение в наносекундах ( текст ссылки )
  3. Статистический анализ. Пусть Y будет временем итерации. Пусть X будет размером массива. Сделайте много измерений Y для различных значений X. График X против Y. Какова форма этого графика? Возможно, вы захотите запустить простую линейную регрессию Y = b0 + b1X, чтобы проверить ваше предположение, что время итерации коррелирует с размером массива.
1 голос
/ 08 сентября 2010

Ваши циклы завершаются так быстро, что миллисекунды недостаточно детализированы, чтобы измерить прошедшее время (завершается гораздо менее чем за 1 мс).

Переключитесь на System.nanoTime() для лучшей детализации.Мой пробег дает мне это:

#2
arrList1 Elapsed Time:9160
arrList2 Elapsed Time:48120
arrList3 Elapsed Time:483080
arrList4 Elapsed Time:150760
arrList5 Elapsed Time:1538880

Обратите внимание на интересное время arrList3.Я бы запустил несколько проходов, чтобы проверить согласованность и переупорядочить прогоны (например, arrList5 сначала до arrList1) и посмотреть, что произойдет.

===

ЦиклНЕ оптимизируется. Это был и мой первый инстинкт, но мне было трудно в это поверить.

Нужно посмотреть на байт-код для подтверждения.Вот байт-код, который Eclipse показывает мне для одного из циклов:

 63  invokestatic java.lang.System.nanoTime() : long [51]
 66  lstore 7 [startTime11]
 68  iconst_0
 69  istore 9 [i]
 71  goto 77
 74  iinc 9 1 [i]
 77  iload 9 [i]
 79  aload 6 [arrList1]
 81  invokevirtual java.util.ArrayList.size() : int [55]
 84  if_icmplt 74
 87  invokestatic java.lang.System.nanoTime() : long [51]
 90  lload 7 [startTime11]
 92  lsub
 93  lstore 9 [total11]
  • Байт 69 - инициализация цикла
  • Байт 74 - приращение
  • Байт 84 - это проверка состояния
0 голосов
/ 08 сентября 2010

Целью упражнения может быть наблюдение за капризами микробенчмаркинга, как описано в Анатомия дефектного микробенчмарка и Написание Java Micro-benchmark .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...