Общее·количество·просмотров·страницы

Java Dev Notes - разработка на Java (а также на JavaScript/Python/Flex и др), факты, события из АйТи

понедельник, 4 мая 2009 г.

Массивы в Java - Часть 3 - Копирование и клонирование - Сравнение производительности

В предыдущем сообщении было рассмотрено 4 способа копирования массивов:

  • используя метод System.arraycopy
  • используя метод clone
  • используя методы Arrays.copyOf или Arrays.copyOfRange
  • провести копирование вручную в цикле

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

Для тестирования нам понадобится таймер. Я использовал следующий класс таймера:

public class Stopwatch {

private long startTime = 0;
private long stopTime = 0;
private boolean running = false;

public void start() {
startTime = System.currentTimeMillis();
running = true;
}

public void stop() {
stopTime = System.currentTimeMillis();
running = false;
}

//elapsed time in milliseconds
public long getElapsedTime() {
long elapsed;
if (running) {
elapsed = (System.currentTimeMillis() - startTime);
} else {
elapsed = (stopTime - startTime);
}
return elapsed;
}

public String toString() {
String result = "" + getElapsedTime() + " ms";
return result;
}
}

Его использование простое: перед началом измеряемой операции вызываем метод start(), после завершения операции вызываем метод stop(). Время, прошедшее между вызовами этих двух методов и является временем, затраченным на выполнение измеряемой операции.

Теперь рассмотрим сам тест. Для сравнения производительности будем вызывать большое количество раз (например, миллион раз) операции копирования, реализованные четырьмя рассмотренными выше способами. После этого замерим время, затраченное на выполнение операции, и сможем сделать вывод, какой способ наиболее производительный. И, важный момент, для оценки будем использовать только производительность интерпретатора Java, т.е. отключим исполнение native code (это достигается опцией java -Xint). Итак, вот код тестового класса:

import java.util.*;

public class ArrayCopyTest {

static void useArraycopy(int[] a, int n) {
int[] copy = new int[a.length];
for (int i=0; i<n; i++)
System.arraycopy(a,0,copy,0,a.length );
}

static void useClone(int[] a, int n) {
int[] copy;
for (int i=0; i<n; i++)
copy = (int[])a.clone();
}

static void useCopyOf(int[] a, int n) {
int[] copy;
for (int i=0; i<n; i++)
copy = Arrays.copyOf(a,a.length);
}

static void useLoop(int[] a, int n) {
int[] copy = new int[a.length];
for (int i=0; i<n; i++)
for (int j=0; j<a.length; j++)
copy[j] = a[j];
}

public static void main(String[] args) {
int n = Integer.parseInt(args[0]);
Stopwatch stopwatch = new Stopwatch();
int[] a = {1,2,3,4,5,6,7,8,9,10};

stopwatch.start();
useClone(a,n);
stopwatch.stop();
System.out.println("Using clone: " + stopwatch);

stopwatch.start();
useArraycopy(a,n);
stopwatch.stop();
System.out.println("Using System.arraycopy: "
+ stopwatch);

stopwatch.start();
useCopyOf(a,n);
stopwatch.stop();
System.out.println("Using Arrays.copyOf: "
+ stopwatch);

stopwatch.start();
useLoop(a,n);
stopwatch.stop();
System.out.println("Using for loop: "
+ stopwatch);
}
}

Выполнение данного кода производится следующей командой (задан миллион итераций):
java -Xint ArrayCopyTest 1000000

Результаты, полученные на моей машине, следующие:

Using clone: 360 ms
Using System.arraycopy: 203 ms
Using Arrays.copyOf: 812 ms
Using for loop: 735 ms

Должен сказать, что цифры слегка изменялись от раза к разу, но, в целом, тенденция такова (методы копирования массива расположены по убыванию производительности):

System.arraycopy
clone
loop
Arrays.copyOf

ВЫВОД: Копирование массивов с использованием System.arraycopy оказывается наиболее производительным методом.

2 комментария:

  1. Этот комментарий был удален автором.

    ОтветитьУдалить
  2. Воркбенч не совсем верный.
    Сравнение useArraycopy и useCopyOf приводит к ложным выводам. Суть состоит в том что судя по реализации java.util.Arrays.copyOf(int[], int) (1.6) разница с useArraycopy только в том, что при copyOf каждньй раз выполняется создание нового массива, в который происходит копирование, а в Вашем методе useArraycopy лиш перед началом выполнения цикла.

    P.S. Извините что роюсь в прошлом:)

    ОтветитьУдалить

Постоянные читатели