IT

for 루프보다 System.arraycopy (…)를 사용하는 것이 더 낫 오류입니까?

lottoking 2020. 9. 16. 07:57
반응형

for 루프보다 System.arraycopy (…)를 사용하는 것이 더 낫 오류입니까?


두 개의 작은 배열을 결합하는 새로운 배열을 만들고 싶습니다.

null 일 수 없지만 크기는 0 일 수 있습니다.

이 두 가지 방법 중 하나를 선택할 수 없습니다. 동등하거나 하나 더 발견입니까 (예 : system.arraycopy () 전체 청크 복사)?

MyObject[] things = new MyObject[publicThings.length+privateThings.length];
System.arraycopy(publicThings, 0, things, 0, publicThings.length);
System.arraycopy(privateThings, 0, things,  publicThings.length, privateThings.length);

또는

MyObject[] things = new MyObject[publicThings.length+privateThings.length];
for (int i = 0; i < things.length; i++) {
    if (i<publicThings.length){
        things[i] = publicThings[i]
    } else {
        things[i] = privateThings[i-publicThings.length]        
    }
}

유일한 차이점은 코드의 모양입니까?

편집 : 해결되지 않은 질문에 감사하지만 해결되지 않은 토론이 있습니다.

it is not for native typesbyte [], Object [], char [] 이면 정말 더 빠릅니까? 다른 모든 경우에는 유형 검사가 실행됩니다. 이것은 내 경우에 동등합니다.

또 다른 경우에는 질문에서 the size matters a lot크기가> 24 인 경우 system.arraycopy ()가 이기고 10보다 작은 경우 수동 루프 for 루프 .

이제 정말 혼란 스러워요.


public void testHardCopyBytes()
{
    byte[] bytes = new byte[0x5000000]; /*~83mb buffer*/
    byte[] out = new byte[bytes.length];
    for(int i = 0; i < out.length; i++)
    {
        out[i] = bytes[i];
    }
}

public void testArrayCopyBytes()
{
    byte[] bytes = new byte[0x5000000]; /*~83mb buffer*/
    byte[] out = new byte[bytes.length];
    System.arraycopy(bytes, 0, out, 0, out.length);
}

나는 JUnit 테스트 정말 벤치마킹을 최적하지 않고
testHardCopyBytes 완료에 0.157s했다

testArrayCopyBytes 완료에 0.086s했다.

가상 머신에 의존 생각하지만 단일 배열 요소를 복사하는 대신 메모리 블록을 복사하는 것처럼 보입니다. 이것은 절대적으로 성능을 향상시키는 것입니다.

편집 :
System.arraycopy의 성능이 온통있는 것입니다. 바이트 대신 배열이 배열이 작 으면 (크기 10) 다음과 같은 결과가 나타납니다.

    String HC:  60306 ns
    String AC:  4812 ns
    byte HC:    4490 ns
    byte AC:    9945 ns

배열의 크기가 0x1000000 일 때의 모습은 다음과 같다. System.arraycopy가 더 큰 배열에서 확실히 승리하는 것처럼 보입니다.

    Strs HC:  51730575 ns
    Strs AC:  24033154 ns
    Bytes HC: 28521827 ns
    Bytes AC: 5264961 ns

얼마나 특이한가!

Daren에게 감사드립니다. 그것은 흥미로운 흥미로운 문제로 만들었습니다!


Arrays.copyOf(T[], int)읽을 수 있습니다. 내부적으로는 System.arraycopy()호출을 사용합니다.

더 빨리 얻을 수 없습니다!


가상 머신에 따라 다르지만 System.arraycopy는 기본 성능에 가장. 한 성능을 제공해야합니다.

저는 강화 시스템 (성능이 가장 중요한 곳)을 자바 개발자로 2 년 동안 사용할 수있는 System.arraycopy를 사용할 수있는 모든 곳에서 대부분 사용했거나 기존 코드에서 사용하는 것을 보았습니다. 성능이 문제 일 때 항상 루프보다 선호됩니다. 성능이 큰 문제가 아니라면 루프를 사용합니다. 누구나 읽을 수 있습니다.


추측과 구식 정보에 의존하는 대신 사용하여 벤치 마크를 실행했습니다 . 실제로 Caliper에는 이 질문을 정확하게 측정하는 것을 포함 하여 가지 예제가 있습니다 ! 당신이해야 할 일 실행CopyArrayBenchmark

mvn exec:java -Dexec.mainClass=com.google.caliper.runner.CaliperMain -Dexec.args=examples.CopyArrayBenchmark

내 결과는 2010 년 중반 MacBook Pro (Intel Arrandale i7, 8GiB RAM이있는 macOS 10.11.6)에서 실행되는 Oracle의 Java HotSpot (TM) 64 비트 서버 VM, 1.8.0_31-b13을 기반으로합니다. 원시 타이밍 데이터를 게시하는 것이 유용하다고 생각하지 않습니다. 추가 지원 기능을 통해 요약하겠습니다.

요약해서 기재 :

  • for각 요소를 새로 인스턴스화 된 배열로 복사 하는 수동 루프를 작성하는 것은 짧은 배열이든 긴 배열이든간에 배열 하는 것이 좋습니다.
  • Arrays.copyOf(array, array.length)그리고 array.clone()둘 다 지속적으로 빠릅니다. 이 두 기술은 성능면에서 거의 동일합니다. 당신이 선택하는 것은 취향의 문제입니다.
  • System.arraycopy(src, 0, dest, 0, src.length)만큼 빠르지 만 일관되지는 않습니다. (50000 s 의 경우를 참조하십시오 .) 그것과 호출의 장황함 때문에 어떤 요소가 어디에서 복사되는지에 대한 미세 제어가 필요한 경우 권장 합니다.Arrays.copyOf(array, array.length)array.clone()intSystem.arraycopy()

타이밍 플롯은 다음과 같습니다.

길이 5 배열 복사 타이밍 길이가 500 인 배열을 복사하기위한 타이밍 길이가 50000 인 배열 복사 타이밍


같은 네이티브 메서드를 실행 Arrays.copyOf(T[], int)하면 약간의 오버 헤드가 있지만 JNI를 사용하여 실행하는 것만 큼 빠르지 않다는 의미는 아닙니다.

가장 쉬운 방법은 벤치 마크를 작성하고 테스트하는 것입니다.

Arrays.copyOf(T[], int)정상적인 for루프 보다 빠른지 확인할 수 있습니다 .

여기 에서 벤치 마크 코드 :-

public void test(int copySize, int copyCount, int testRep) {
    System.out.println("Copy size = " + copySize);
    System.out.println("Copy count = " + copyCount);
    System.out.println();
    for (int i = testRep; i > 0; --i) {
        copy(copySize, copyCount);
        loop(copySize, copyCount);
    }
    System.out.println();
}

public void copy(int copySize, int copyCount) {
    int[] src = newSrc(copySize + 1);
    int[] dst = new int[copySize + 1];
    long begin = System.nanoTime();
    for (int count = copyCount; count > 0; --count) {
        System.arraycopy(src, 1, dst, 0, copySize);
        dst[copySize] = src[copySize] + 1;
        System.arraycopy(dst, 0, src, 0, copySize);
        src[copySize] = dst[copySize];
    }
    long end = System.nanoTime();
    System.out.println("Arraycopy: " + (end - begin) / 1e9 + " s");
}

public void loop(int copySize, int copyCount) {
    int[] src = newSrc(copySize + 1);
    int[] dst = new int[copySize + 1];
    long begin = System.nanoTime();
    for (int count = copyCount; count > 0; --count) {
        for (int i = copySize - 1; i >= 0; --i) {
            dst[i] = src[i + 1];
        }
        dst[copySize] = src[copySize] + 1;
        for (int i = copySize - 1; i >= 0; --i) {
            src[i] = dst[i];
        }
        src[copySize] = dst[copySize];
    }
    long end = System.nanoTime();
    System.out.println("Man. loop: " + (end - begin) / 1e9 + " s");
}

public int[] newSrc(int arraySize) {
    int[] src = new int[arraySize];
    for (int i = arraySize - 1; i >= 0; --i) {
        src[i] = i;
    }
    return src;
}

System.arraycopy()JNI (Java Native Interface)를 사용하여 배열 (또는 그 일부)을 복사하므로 여기에서 확인할 수 있듯이 매우 빠릅니다.


이것이 다음의 구현이기 때문에 Arrays.copyOf더 빠를 수는 없습니다 .System.arraycopycopyOf

public static int[] copyOf(int[] original, int newLength) {
    int[] copy = new int[newLength];
    System.arraycopy(original, 0, copy, 0,
                     Math.min(original.length, newLength));
    return copy;
}

System.arraycopy()메모리에서 직접 복사 작업을 수행하는 기본 호출입니다. 단일 메모리 복사본은 항상 for 루프보다 빠릅니다.

참고 URL : https://stackoverflow.com/questions/18638743/is-it-better-to-use-system-arraycopy-than-a-for-loop-for-copying-arrays

반응형