source

시스템을 사용하는 것이 좋습니까?어레이를 복사하기 위한 for 루프가 아닌 arraycopy(...)를 선택하십시오.

goodcode 2022. 9. 3. 13:17
반응형

시스템을 사용하는 것이 좋습니까?어레이를 복사하기 위한 for 루프가 아닌 arraycopy(...)를 선택하십시오.

2개의 작은 어레이를 조합한 새로운 오브젝트 어레이를 만들고 싶습니다.

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

나는 이 두 가지 방법 중 하나를 선택할 수 없다: 그것들이 동등한가 아니면 더 효율적인가(예를 들어 시스템).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]        
    }
}

유일한 차이점은 코드의 외관뿐입니까?

EDIT: 링크된 질문 감사합니다만, 아직 해결되지 않은 논의가 있는 것 같습니다.

정말 더 빠른가요?it is not for native types: byte[ ] , " 오 、 char [ ] 합니까?아니죠다른 모든 경우, 활자체크가 실행되는데, 내 경우 같다면... 아닌가?

연계된에서는 '하다, , 하다'the size matters a lot> system size > 24 "size" > "size. 경우arraycopy() 보보10 보 array array array array array 。

지금 나는 정말 혼란스럽다.

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의 경우
는 HardCopyBytes를 완료하는 데 0..
...
0..testArrayCopyBytes는 0.086s입니다.

가상 머신에 따라 다르지만 단일 어레이 요소를 복사하는 대신 메모리 블록을 복사하는 것처럼 보입니다.이치노

★★★★★★
스스 arraycopy のanceanceanceanceanceance 。바이트 대신 문자열이 사용되고 배열이 작은 경우(사이즈 10) 다음과 같은 결과가 나타납니다.

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

어레이의 사이즈가 0x1000000일 때의 모습을 다음에 나타냅니다.시스템처럼 보여요.어레이 복사는 대규모 어레이에서 확실히 유리합니다.

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

★★★★★★★★★★★★★★★★!

대런 씨, 참고 문헌이 다르게 복사된다는 점을 지적해 주셔서 감사합니다.그것은 이것을 훨씬 더 흥미로운 문제로 만들었다!

Arrays.copyOf(T[], int)가 읽기 쉬워집니다.에서는 「」를 사용합니다.System.arraycopy()네이티브 콜입니다.

더 빨리 할 수 없어!

가상 시스템에 따라 다르지만 시스템에 따라 다릅니다.arraycopy를 사용하면 네이티브 퍼포먼스에 가장 가까운 성능을 얻을 수 있습니다.

저는 임베디드 시스템(성능이 중요한 곳) 및 모든 시스템용 자바 개발자로 2년간 일해 왔습니다.Arraycopy를 사용할 수 있습니다.기존 코드에서 사용하는 것을 대부분 사용하고 있습니다.퍼포먼스가 문제가 될 때는 루프보다 항상 우선합니다.퍼포먼스가 큰 문제가 되지 않는다면 루프로 하겠습니다.훨씬 읽기 쉬워요.

추측이나 오래된 정보에 의존하는 대신 캘리퍼를 하여 몇 가지 벤치마크를 실행했습니다.실제로 캘리퍼에는 이 질문을 정확하게 측정하는 를 포함한 몇 가지 예가 포함되어 있습니다.넌 도망치기만 하면 돼

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

결과는 2010년 중반의 MacBook Pro(인텔 Arrandale i7, 8 GiB RAM 탑재 MacOS 10.11.6)에서 실행되는 Oracle의 Java HotSpot(TM) 64비트 서버 VM 1.8.0_31-b13을 기반으로 합니다.원시 타이밍 데이터를 게시하는 것은 유용하지 않다고 생각합니다.대신, 결론을 뒷받침하는 시각화와 함께 요약하겠습니다.

요약:

  • 매뉴얼 작성for각 요소를 새로 인스턴스화된 어레이에 복사하는 루프는 짧은 어레이든 긴 어레이든 결코 유리하지 않습니다.
  • Arrays.copyOf(array, array.length) 둘 다 일관되게 빠릅니다.이 두 기술은 성능 면에서 거의 동일합니다. 어느 것을 선택하느냐는 취향의 문제입니다.
  • System.arraycopy(src, 0, dest, 0, src.length) 거의 와 같은 속도이다Arrays.copyOf(array, array.length)그리고.array.clone()단, 그다지 일관성이 있는 것은 아닙니다.(50000 의 경우는, 케이스를 참조해 주세요).ints) 그 때문에, 콜의 장황함도 추천합니다.System.arraycopy()어떤 요소가 어디에 복사되는지를 세밀하게 제어해야 할 경우.

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

길이 5의 어레이 복사 타이밍 길이 500의 어레이 복사 타이밍 길이 50000의 어레이 복사 타이밍

할 수 없다Arrays.copyOf보다 빠르다System.arraycopy이것이 실시이기 때문에copyOf:

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;
}

다음과 같은 네이티브 메서드 실행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)를 사용하여 어레이(또는 일부)를 복사하기 때문에 여기서 확인할 수 있듯이 매우 고속입니다.

System.arraycopy()는 메모리에서 직접 복사 조작을 실행하는 네이티브콜입니다단일 메모리 복사는 항상 for 루프보다 빠릅니다.

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

반응형