问题描述
我试图了解如何利用多线程的优势.我编写了一个简单的程序,使用两种方式将i
的值递增40万次:单线程方式(0到400,000)和多线程方式(在我的情况下,是4倍:0到100,000),线程数等于Runtime.getRuntime().availableProcessors()
.
I'm trying to understand how to take advantage of using multi threads. I wrote a simple program that increments the value of i
, let's say, 400,000 times using two ways : a single threaded way (0 to 400,000) and a multiple threaded way (in my case, 4 times : 0 to 100,000) with the number of thread equal to Runtime.getRuntime().availableProcessors()
.
我对自己的测量结果感到惊讶:单线程方式明显更快,有时甚至快了3倍.这是我的代码:
I'm surprised with the results I measured : the single threaded way is decidedly faster, sometimes 3 times faster. Here is my code :
public class Main {
public static int LOOPS = 100000;
private static ExecutorService executor=null;
public static void main(String[] args) throws InterruptedException, ExecutionException {
int procNb = Runtime.getRuntime().availableProcessors();
long startTime;
long endTime;
executor = Executors.newFixedThreadPool(procNb);
ArrayList<Calculation> c = new ArrayList<Calculation>();
for (int i=0;i<procNb;i++){
c.add(new Calculation());
}
// Make parallel computations (4 in my case)
startTime = System.currentTimeMillis();
queryAll(c);
endTime = System.currentTimeMillis();
System.out.println("Computation time using " + procNb + " threads : " + (endTime - startTime) + "ms");
startTime = System.currentTimeMillis();
for (int i =0;i<procNb*LOOPS;i++)
{
}
endTime = System.currentTimeMillis();
System.out.println("Computation time using main thread : " + (endTime - startTime) + "ms");
}
public static List<Integer> queryAll(List<Calculation> queries) throws InterruptedException, ExecutionException {
List<Future<Integer>> futures = executor.invokeAll(queries);
List<Integer> aggregatedResults = new ArrayList<Integer>();
for (Future<Integer> future : futures) {
aggregatedResults.add(future.get());
}
return aggregatedResults;
}
}
class Calculation implements Callable<Integer> {
@Override
public Integer call() {
int i;
for (i=0;i<Main.LOOPS;i++){
}
return i;
}
}
控制台:
Computation time using 4 threads : 10ms.
Computation time using main thread : 3ms.
Computation time using 4 threads : 10ms.
Computation time using main thread : 3ms.
有人可以解释吗?
推荐答案
加法可能需要一个cpu周期,因此,如果您的cpu以3 GHz运行,则为0.3纳秒.进行40万次,则变为120k纳秒或0.1毫秒.因此,您的测量受启动线程,线程切换,JIT编译等开销的影响比受您尝试测量的操作的影响更大.
An addition probably takes one cpu cycle, so if your cpu runs at 3GHz, that's 0.3 nanoseconds. Do it 400k times and that becomes 120k nanoseconds or 0.1 milliseconds. So your measurement is more affected by the overhead of starting threads, thread switching, JIT compilation etc. than by the operation you are trying to measure.
您还需要考虑编译器的优化:如果将空循环放置在方法中并运行多次,您会注意到它在一段时间后在0毫秒内运行.因为编译器确定循环不执行任何操作并对其进行了完全优化.
You also need to account for the compiler optimisations: if you place your empty loop in a method and run that method many times you will notice that it runs in 0 ms after some time,. because the compiler determines that the loop does nothing and optimises it away completely.
我建议您使用专门的库进行微基准测试,例如 jmh .
I suggest you use a specialised library for micro benchmarking, such as jmh.
另请参阅:如何编写正确的Java中的微基准测试?
这篇关于java-多线程中的简单计算比单线程中的花费更长的时间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!