Я написал код 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)" );
}
}