문제

는데,멀티 스레딩 java 응용 프로그램에서 실행되는 Nehalem 프로세서입니다.그러나 내가 문제가 있는 것에서 시작하는 4 개의 스레드가 거의 보이지 않 속도 향상에 내 응용 프로그램이 있습니다.

나는 몇 가지 간단한 시험입니다.나가사는 할당한다 큰 배열에 대한 액세스를 임의 항목 배열입니다.그래서 실행할 때의 번호를 스레드 실행 시간은 변화하면 안된다면(내 초과하지 않는 번호의 사용 가능한 CPU core).하지만 제가 관찰되는 실행하는 1 또는 2 개 스레드가 거의 동일한 시간만 실행하는 4 또는 8 개의 스레드가 크게 느립니다.그래서 전에도하도록 해결하는 알고리즘과 동기화 문제 응용 프로그램에서 내가 원하는 무엇을 찾은 최대한 가능한 병렬화가할 수 있을 것으로 기대하고 있다.

-XX:+UseNUMA JVM 옵션이므로,배는 해야 할당되는 메모리에 근처에는 해당 스레드입니다.

P.S.는 경우에 스레드를 만들고 있었는 간단한 수학적 계산 시간이 없었 드롭 4 8threads,그래서 나는 결론을 내렸을 때 스레드에 액세스하는 메모리가 어떤 문제입니다.

어떤 도움이나 아이디어는 평가,감사합니다.


편집

주셔서 감사합니다 모두들에 대한 답변.나오지 않았는지 설명했다 나 자신도 충분합니다.

기 전에 제거하기 위해 노력하고 동기화 문제 응용 프로그램에서 내가 만들어 간단하는 테스트를 확인 최고의 가능한 병렬화는 달성될 수 있었습니다.이 코드는 다음과 같습니다:

public class TestMultiThreadingArrayAccess {
    private final static int arrSize = 40000000;

    private class SimpleLoop extends Thread {
        public void run() {
            int array[] = new int[arrSize];
            for (long i = 0; i < arrSize * 10; i++) {
                array[(int) ((i * i) % arrSize)]++; // randomize a bit the access to the array
            }
            long sum = 0;
            for (int i = 0; i < arrSize; i++)
                sum += array[i];
        }
    }

    public static void main(String[] args) {
        TestMultiThreadingArrayAccess test = new TestMultiThreadingArrayAccess();
        for (int threadsNumber : new int[] { 1, 2, 4, 8 }) {
            Statistics timer = new Statistics("Executing " + threadsNumber+ " threads"); // Statistics is a simple helper class that measures the times
            timer.start();
            test.doTest(threadsNumber);
            timer.stop();
            System.out.println(timer.toString());
        }
    }

    public void doTest(int threadsNumber) {
        Thread threads[] = new Thread[threadsNumber];
        for (int i = 0; i < threads.length; i++) {
            threads[i] = new SimpleLoop();
            threads[i].start();
        }

        for (int i = 0; i < threads.length; i++)
            try {
                threads[i].join();
            } catch (InterruptedException e) {
            };
    }
}

그래서 당신이 볼 수 있는 동기화 모두에서 이 minitest 및 할당 배열의 내부 실무에 배치해야의 덩어리는 메모리 액세스할 수 있다.또한 없다는 메모리라 이에서 다툼에 이 코드입니다.전을 위한 4 개의 스레드가 하락의 30%에서 실행 시간,그리고 8 개 스레드를 실행되는 두 번 느립니다.당신이 코드에서 내가 기다릴 때까지 모든 실무 그들의 작업,그리고 그 이후 그들의 작품은 독립적인 스레드 개수에 영향을 미치지 않는 총 시간을 실행합니다.

기계에 설치 2quad-core hyperthreaded Nehalem 프로세서(완전 16Cpu),그래서 8 개의 스레드를 각각 하나를 잡을 수 있는것은 CPU 가 중점을 두고 있었습니다.

전라북도 전주시 완산구 경 이 테스트는 작은 배열(20K 항목)의 삭제 실행 시간의 4 스레드었 7%및 8 개의 스레드-14%는 만족입니다.그러나 시도할 때,작동하는 임의의 접근에 큰 배열(40M 항목)실행 시간이 크게 증가,그래서 나는 생각한 문제를 지니고 있다는 큰 덩어리의 메모(기 때문에 맞지 않는 캐시 메모리?) 액세스 non 효율적인 방식으로 수행합니다.

어떤 아이디어를 수정하는 방법 이?

희망이 명확하게 질문을 더 나은 방법으로,다시 한번 감사드립니다.

도움이 되었습니까?

해결책

에서 병목 현상의 테스트는 cpu 메모리에 대역폭.을 때에도 지역 메모리를 사용할 수 있는지,그것을 공유할 의 일부 스레드 수입니다.(이 메모리는 현지 노드,하지 않는 특정한 핵심입니다.) 일단 CPU 쉽게 할 수 있을 초과한 사용할 수 있는 대역폭을 위한 간단한 루프의 위의 테스트,그리고 증가하는 스레드에서 이러한 테스트는 성능이 향상되지 않습과 악화시킬 수 있는 성능으로 인하여 악화된 캐시에 일관성이다.

다만 정신 테스트,당신은 또한 사용하여 병렬 수 있나요? -XX:+UseParallelGC.UseNUMA 효과만 다음입니다.

다른 팁

당신이 정확히 무엇을하고 있는지 모른다. 그리고 당신의 해결하려는 문제는 무엇인지 알지 못한다. 확장 가능하지 않은 주요 이유가 될 수 있기 때문에 코드 주변에 무거운 동기화가있는 것처럼 보입니다. 동기화 오버 원인은 빠른 속도를 늦추어 응용 프로그램을 거의 직렬로 만듭니다. 그래서 당신에게 나의 제안은 구현을 검사하고 이것을 알아 내려고 노력하는 것입니다.

add.

당신이하는 일을 구현 한 후에 성능의 다운 그레이드는 크고 대규모 메모리 액세스로 설명 될 수 있습니다. 스레드를 모두 실행하고 캐시 된 데이터가 아닌 메모리 컨트롤러에 액세스해야합니다. 다른 CPU에서 실행되지 않으므로 메모리 컨트롤러가 CPU가 동시에 수행하는 것을 방지합니다. 즉, 각 캐시 미스에 하드웨어 레벨에서 동기화가 발생합니다. 귀하가 대소 문자로 10 가지 독립 프로그램을 실행하는 것과 거의 동일합니다. 예를 들어, 웹 브라우저를 복사 할 수있는 10 개를 실행하면 동일한 효과가 표시되지만 브라우저 구현이 비효율적이라는 것을 의미하는 것은 아닙니다. 컴퓨터 메모리.

Artem Notes로서는 불필요한 동기화가 가능할 수 있습니다. 그러나 나는 사실을 확립함으로써 시작합니다. 앱을 설명하면서 앱이 실제로 느리게 작동합니까?

여기 주제에 대한 통찰력있는 기사입니다. http://codeol.com/java/java-concurrency/testing-concurrent-programs/avoiding-performance-testing-pitfalls/

실제로 동시 코드를 처리 할 때 유용한 마이크로 벤치 마크를 작성하는 것이 매우 어렵습니다. 예를 들어 컴파일러가 실행중인 코드를 최적화하는 "데드 코드 제거"가있을 수 있습니다. 가비지 수집이 실행될 때 추측하기가 어렵습니다. 핫스팟의 런타임 최적화는 또한 측정을보다 어렵게 만듭니다. 스레드의 경우, 사용자가 생성하는 데 사용되는 시간을 고려해야합니다. 따라서 정확한 측정을 위해`Cyclicbarrier` 등을 사용해야 할 수도 있습니다. 그런 것들을 ..

당신이하고있는 일이 모두 읽는다면 메모리에 액세스하는 데 문제가 있음을 알게되었다고 말했습니다. 코드를 게시 할 수 있다면 우리는 당신을 더 잘 도울 수 있습니다 ...

두 가지 분명한 잠재적 인 문제가 있습니다.

  • 더 많은 thread를 사용하면 캐시를 버린 더 많은 배열을 할당합니다.주 메모리 또는 낮은 캐시에 대한 액세스는 훨씬 느려집니다.
  • 난수 생성기의 동일한 인스턴스의 동일한 원인을 사용하는 경우 스레드가 액세스를 통해 싸우게됩니다.완전한 동기화가 아니라 잠금없는 알고리즘이있는 장벽을 기억할 수 있습니다.일반적으로 잠금없는 알고리즘은 일반적으로 빠르지 만 높은 경쟁에서 훨씬 더 느리게 만듭니다.

동시성 문제를 제외하고 느리게의 원인은 메모리 캐시 경합입니다.

모든 스레드가 동일한 저장소에 액세스하는 경우 다른 프로세서 메모리 캐시에 액세스 할 가능성이 있습니다.

스토리지가 "읽기 전용"이면 JVM 및 프로세서가 메모리 acccesses를 최적화하도록 허용하는 각 스레드를 제공 할 수 있습니다.

제가 게시 한 기사의 조언으로 테스트를 수정했습니다.내 2 개의 코어 기계 (그게 지금 당장의 모든 것이 있음) 결과가 합리적으로 보입니다 (각 스레드 번호마다 2 테스트 2 테스트) :

어쩌면 이것을 시도 할 수 있습니까? (가난한 하드웨어에서 실행이 오래 걸리기 때문에 테스트를 약간 수정해야합니다.)

또한 -server 옵션을 사용 하여이 테스트를 실행합니다.

Test with threadNum 1 took 2095717473 ns
Test with threadNum 1 took 2121744523 ns
Test with threadNum 2 took 2489853040 ns
Test with threadNum 2 took 2465152974 ns
Test with threadNum 4 took 5044335803 ns
Test with threadNum 4 took 5041235688 ns
Test with threadNum 8 took 10279012556 ns
Test with threadNum 8 took 10347970483 ns
.

코드 :

import java.util.concurrent.*;

public class Test{
    private final static int arrSize = 20000000;

    public static void main(String[] args) throws Exception {
        int[] nums = {1,1,2,2,4,4,8,8};//allow hotspot optimization
        for (int threadNum : nums) {
            final CyclicBarrier gate = new CyclicBarrier(threadNum+1);
            final CountDownLatch latch = new CountDownLatch(threadNum);
            ExecutorService exec = Executors.newFixedThreadPool(threadNum);
            for(int i=0; i<threadNum; i++){
                Runnable test = 
                  new Runnable(){
                     public void run() {
                         try{
                             gate.await();
                         }catch(Exception e){
                             throw new RuntimeException(e);
                         }
                         int array[] = new int[arrSize];
                         //arrSize * 10 took very long to run so made it
                         // just arrSize.
                         for (long i = 0; i < arrSize; i++) {
                             array[(int) ((i * i) % arrSize)]++;
                         }//for
                         long sum = 0;
                         for (int i = 0; i < arrSize; i++){
                              sum += array[i]; 
                         }
                         if(new Object().hashCode()==sum){
                              System.out.println("oh");
                         }//if
                         latch.countDown();
                      }//run
                   };//test
                exec.execute(test);
             }//for
             gate.await();
             long start = System.nanoTime();
             latch.await();
             long finish = System.nanoTime();
             System.out.println("Test with threadNum " +
                 threadNum +" took " + (finish-start) + " ns ");
             exec.shutdown();
             exec.awaitTermination(Long.MAX_VALUE,TimeUnit.SECONDS);           
        }//for
    }//main

}//Test
.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top