我要实现的任务是使用多个线程在设定的间隔中找到数字的Collatz序列,并查看与一个线程相比有多少改进。
但是无论我选择2个线程,一个线程总是总是更快的(编辑.2个线程更快,但是4个线程比1个线程慢,而且速度不算多,我也不知道为什么。(我什至可以说更多的线程我希望有人能解释。也许我做错了。
以下是我到目前为止编写的代码。我正在使用ThreadPoolExecutor执行任务(一个任务=一个Collatz序列,一个间隔中的一个数字)。
Collatz类:
public class ParallelCollatz implements Runnable {
private long result;
private long inputNum;
public long getResult() {
return result;
}
public void setResult(long result) {
this.result = result;
}
public long getInputNum() {
return inputNum;
}
public void setInputNum(long inputNum) {
this.inputNum = inputNum;
}
public void run() {
//System.out.println("number:" + inputNum);
//System.out.println("Thread:" + Thread.currentThread().getId());
//int j=0;
//if(Thread.currentThread().getId()==11) {
// ++j;
// System.out.println(j);
//}
long result = 1;
//main recursive computation
while (inputNum > 1) {
if (inputNum % 2 == 0) {
inputNum = inputNum / 2;
} else {
inputNum = inputNum * 3 + 1;
}
++result;
}
// try {
//Thread.sleep(10);
//} catch (InterruptedException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
//}
this.result=result;
return;
}
}
还有运行线程的主类(是的,我现在创建两个具有相同编号的列表,因为使用一个线程运行后,初始值会丢失):
ThreadPoolExecutor executor = (ThreadPoolExecutor)Executors.newFixedThreadPool(1);
ThreadPoolExecutor executor2 = (ThreadPoolExecutor)Executors.newFixedThreadPool(4);
List<ParallelCollatz> tasks = new ArrayList<ParallelCollatz>();
for(int i=1; i<=1000000; i++) {
ParallelCollatz task = new ParallelCollatz();
task.setInputNum((long)(i+1000000));
tasks.add(task);
}
long startTime = System.nanoTime();
for(int i=0; i<1000000; i++) {
executor.execute(tasks.get(i));
}
executor.shutdown();
boolean tempFirst=false;
try {
tempFirst =executor.awaitTermination(5, TimeUnit.HOURS);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.out.println("tempFirst " + tempFirst);
long endTime = System.nanoTime();
long durationInNano = endTime - startTime;
long durationInMillis = TimeUnit.NANOSECONDS.toMillis(durationInNano); //Total execution time in nano seconds
System.out.println("laikas " +durationInMillis);
List<ParallelCollatz> tasks2 = new ArrayList<ParallelCollatz>();
for(int i=1; i<=1000000; i++) {
ParallelCollatz task = new ParallelCollatz();
task.setInputNum((long)(i+1000000));
tasks2.add(task);
}
long startTime2 = System.nanoTime();
for(int i=0; i<1000000; i++) {
executor2.execute(tasks2.get(i));
}
executor2.shutdown();
boolean temp =false;
try {
temp=executor2.awaitTermination(5, TimeUnit.HOURS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("temp "+ temp);
long endTime2 = System.nanoTime();
long durationInNano2 = endTime2 - startTime2;
long durationInMillis2 = TimeUnit.NANOSECONDS.toMillis(durationInNano2); //Total execution time in nano seconds
System.out.println("laikas2 " +durationInMillis2);
例如,使用一个线程运行,它将在3280毫秒内完成。用两个线程运行3437ms。我是否应该考虑另一个并发结构来计算每个元素?
编辑澄清。我不是在尝试并行化单个序列,而是在每个数字都有其序列时间隔一个数字。(这与其他数字无关)
编辑2
今天,我在具有6个核心和12个逻辑处理器的PC上运行了该程序,问题仍然存在。有谁知道问题可能在哪里?我还更新了代码。4个线程由于某些原因比2个线程差(甚至比1个线程差)。我也应用了答案中给出的内容,但没有任何变化。
另一个Edit我注意到的是,如果我将Thread.sleep(1)放在ParallelCollatz方法中,则性能会随着线程数的增加而逐渐提高。也许这个细节告诉别人什么地方出了问题?但是,如果没有Thread.Sleep(1),无论我执行多少任务,两个线程的执行速度最快,另一个线程排在第二位,其他线程则挂起类似的毫秒数,但都比1和2个线程慢。
New Edit我还尝试在Runnable类的run()方法中放置更多任务(用于计算不是1而是10或100个Collatz序列的循环),以便线程本身可以完成更多工作。不幸的是,这也没有帮助。也许我启动任务不正确?任何想法吗?
编辑因此,在向run方法添加更多任务后,似乎可以对其进行一些修复,但是对于更多线程,该问题仍然保持8+。我仍然想知道这是因为创建和运行线程要比执行任务花费更多的时间吗?还是应该针对这个问题创建新帖子?
您不是在等待任务完成,而是在衡量将其提交给执行者所需的时间。
executor.shutdown()
不会等待所有任务完成。您需要在此executor.awaitTermination
之后致电。
executor.shutdown();
executor.awaitTermination(5, TimeUnit.HOURS);
https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html#shutdown()
更新我相信我们的测试方法存在缺陷。我在我的机器(1个处理器,2个内核,4个逻辑处理器)上重复了测试,并且每次运行所花费的时间差异很大。
我认为以下是主要原因:
为了对此进行测试,我将您的测试转换为JMH。特别是:
我在下面收到的结果符合我的期望:一个核心在主线程中等待,工作在单个核心上执行,数量几乎相同。
Benchmark Mode Cnt Score Error Units
SpeedTest.multipleThreads avgt 20 559.996 ± 20.181 ms/op
SpeedTest.singleThread avgt 20 562.048 ± 16.418 ms/op
更新的代码:
public class ParallelCollatz implements Callable<Long> {
private final long inputNumInit;
public ParallelCollatz(long inputNumInit) {
this.inputNumInit = inputNumInit;
}
@Override
public Long call() {
long result = 1;
long inputNum = inputNumInit;
//main recursive computation
while (inputNum > 1) {
if (inputNum % 2 == 0) {
inputNum = inputNum / 2;
} else {
inputNum = inputNum * 3 + 1;
}
++result;
}
return result;
}
}
和基准本身:
@State(Scope.Benchmark)
public class SpeedTest {
private static final int NUM_TASKS = 1000000;
private static List<ParallelCollatz> tasks = buildTasks();
@Benchmark
@Fork(value = 1, warmups = 1)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@SuppressWarnings("unused")
public long singleThread() throws Exception {
ThreadPoolExecutor executorOneThread = (ThreadPoolExecutor) Executors.newFixedThreadPool(1);
return measureTasks(executorOneThread, tasks);
}
@Benchmark
@Fork(value = 1, warmups = 1)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@SuppressWarnings("unused")
public long multipleThreads() throws Exception {
ThreadPoolExecutor executorMultipleThread = (ThreadPoolExecutor) Executors.newFixedThreadPool(4);
return measureTasks(executorMultipleThread, tasks);
}
private static long measureTasks(ThreadPoolExecutor executor, List<ParallelCollatz> tasks) throws InterruptedException, ExecutionException {
long sum = runTasksInExecutor(executor, tasks);
return sum;
}
private static long runTasksInExecutor(ThreadPoolExecutor executor, List<ParallelCollatz> tasks) throws InterruptedException, ExecutionException {
List<Future<Long>> futures = new ArrayList<>(NUM_TASKS);
for (int i = 0; i < NUM_TASKS; i++) {
Future<Long> f = executor.submit(tasks.get(i));
futures.add(f);
}
executor.shutdown();
boolean tempFirst = false;
try {
tempFirst = executor.awaitTermination(5, TimeUnit.HOURS);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
long sum = 0l;
for (Future<Long> f : futures) {
sum += f.get();
}
//System.out.println(sum);
return sum;
}
private static List<ParallelCollatz> buildTasks() {
List<ParallelCollatz> tasks = new ArrayList<>();
for (int i = 1; i <= NUM_TASKS; i++) {
ParallelCollatz task = new ParallelCollatz((long) (i + NUM_TASKS));
tasks.add(task);
}
return tasks;
}
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句