Почему этот код не показывает значительного увеличения производительности, когда я использую несколько потоков на машине с четырьмя ядрами?

Я написал код Java, чтобы узнать больше о структуре Executor.

В частности, я написал код для проверки Гипотезы Коллатца - это говорит о том, что если вы итеративно примените следующую функцию к любому целому числу, в конечном итоге вы получите 1:

f (n) = (( п% 2) == 0)? n / 2: 3 * n + 1

CH все еще недоказан, и я подумал, что это будет хороший способ узнать об Executor. Каждому потоку назначается диапазон [l, u] целых чисел для проверки.

В частности, моя программа принимает 3 аргумента - N (число, для которого я хочу проверить CH), RANGESIZE (длина интервала, в котором поток должен обрабатывать), и NTHREAD, размер пула потоков.

Мой код работает нормально, но я увидел гораздо меньшее ускорение, чем ожидал - порядка 30%, когда я перешел с 1 на 4 потока.

Моя логика заключалась в том, что вычисления полностью связаны с процессором, и каждая подзадача (проверка CH на предмет фиксированного диапазона размеров) занимает примерно одинаковое время.

Есть ли у кого-нибудь идеи относительно того, почему я не вижу 3 в 4 раза увеличить скорость?

Если бы вы могли сообщать о времени выполнения по мере увеличения количества потоков (вместе с машиной, JVM и ОС), это тоже было бы здорово.

Особенности

Время выполнения:

java -d64 -сервер -cp. Collatz 10000000 1000000 4 => 4 потока, занимает 28412 миллисекунд

java -d64 -server -cp. Collatz 10000000 1000000 1 => 1 поток, занимает 38286 миллисекунд

Процессор:

Quadcore Intel Q6600 на 2,4 ГГц, 4 ГБ. Машина выгружена.

Java:

версия java "1.6.0_15" Среда выполнения Java (TM) SE (сборка 1.6.0_15-b03) 64-разрядная серверная виртуальная машина Java HotSpot (TM) (сборка 14.1-b02, смешанный режим)

ОС:

Linux quad0 2.6.26-2-amd64 # 1 SMP Вт, 9 марта, 22:29:32 UTC 2010 x86_64 Код GNU / Linux

: (Я не могу получить код для публикации, я думаю, что он слишком длинный для требований SO, исходный код доступен в Google Docs

import java.math.BigInteger;
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class MyRunnable implements Runnable {
  public int lower;
  public int upper;

  MyRunnable(int lower, int upper) {
    this.lower = lower;
    this.upper = upper;
  }

  @Override
  public void run() {
    for (int i = lower ; i <= upper; i++ ) {
      Collatz.check(i);
    }
    System.out.println("(" + lower + "," + upper + ")" );
  }
}


public class Collatz {

  public static boolean check( BigInteger X ) {
    if (X.equals( BigInteger.ONE ) ) {
      return true;
    } else if ( X.getLowestSetBit() == 1 ) { 
      // odd
      BigInteger Y = (new BigInteger("3")).multiply(X).add(BigInteger.ONE);
      return check(Y);
    } else {
      BigInteger Z = X.shiftRight(1); // fast divide by 2
      return check(Z);
    }
  }

  public static boolean check( int x ) {
    BigInteger X = new BigInteger( new Integer(x).toString() );
    return check(X);
  }

  static int N = 10000000;
  static int RANGESIZE = 1000000;
  static int NTHREADS = 4;

  static void parseArgs( String [] args ) {

    if ( args.length >= 1 ) {
      N = Integer.parseInt(args[0]);
    }
    if ( args.length >= 2 ) {
      RANGESIZE = Integer.parseInt(args[1]);
    }
    if ( args.length >= 3 ) {
      NTHREADS = Integer.parseInt(args[2]);
    }
  }

  public static void maintest(String [] args ) {
    System.out.println("check(1): " + check(1));
    System.out.println("check(3): " + check(3));
    System.out.println("check(8): " + check(8));
    parseArgs(args);
  }

  public static void main(String [] args) {
    long lDateTime = new Date().getTime();
    parseArgs( args );
    List threads = new ArrayList();
    ExecutorService executor = Executors.newFixedThreadPool( NTHREADS );
    for( int i = 0 ; i < (N/RANGESIZE); i++) {
      Runnable worker = new MyRunnable( i*RANGESIZE+1, (i+1)*RANGESIZE );
      executor.execute( worker );
    }
    executor.shutdown();
    while (!executor.isTerminated() ) {
    }
    System.out.println("Finished all threads");
    long fDateTime = new Date().getTime();
    System.out.println("time in milliseconds for checking to " + N + " is " + 
                            (fDateTime - lDateTime )  + 
                            " (" + N/(fDateTime - lDateTime ) + " per ms)" );
  }
}

9
задан AShelly 20 July 2011 в 19:17
поделиться