我有一个四核cpu,我出于性能原因试图尝试多线程。我已经在下面编写了这段代码,只是为了看看它的速度有多快,而且我注意到它实际上比只使用主线程的第二个代码块慢了
int numCrunchers = Runtime.getRuntime().availableProcessors();
public void crunch() {
int numPairs = 1000;
for(int i=0; i < numPairs; i++)
pairs.add(...);
int share = pairs.size()/numCrunchers;
for(int i=0; i < numCrunchers; i++) {
Cruncher cruncher = crunchers.get(i);
for(int j=0; j < share; j++)
cruncher.nodes.add(pairs.poll());
}
for(Cruncher cruncher : crunchers)
threadpool.execute(cruncher);
threadpool.shutdown();
try {
threadpool.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private class Cruncher implements Runnable {
public BlockingQueue<Pair<PathNode>> nodes = new LinkedBlockingQueue<Pair<PathNode>>();
private AStarPathfinder pathfinder;
private LinkedList<PathNode> path = new LinkedList<PathNode>();
public Cruncher(GridGraph graph) {
pathfinder = new AStarPathfinder(graph);
}
@Override
public void run() {
while(true) {
path.clear();
Pair<PathNode> pair = nodes.poll();
if(pair != null) {
pathfinder.search(path, pair.first(), pair.second());
paths.add(new LinkedList<PathNode>(path));
} else {
System.out.println("This cruncher is done");
break;
}
}
}
}
每个线程在我的电脑上花费了大约34,000,000,000纳秒,但是当我决定使用除主线程之外没有线程时,它只需要1,090,195,046纳秒,34倍的时差。
LinkedList<Pair<PathNode>> pairs = new LinkedList<Pair<PathNode>>();
int numPairs = 1000;
AStarPathfinder pathfinder = new AStarPathfinder(graph);
for(int i=0; i < numPairs; i++)
pairs.add(...);
long current = System.nanoTime();
for(int i=0; i < numPairs; i++) {
Pair<PathNode> pair = pairs.poll();
path.clear();
pathfinder.search(path, pair.first(), pair.second());
}
System.out.printf("Operation took %d nanoseconds", System.nanoTime() - current);
我的问题是为什么使用多个线程导致程序运行缓慢?代码是不是正确地利用了我的cpu上的所有内核?我运行了几次,结果相似,(30+)x多线程和单线程之间的时差
修改: 决定测量多线程上每个单独操作的时间
while(true) {
path.clear();
Pair<PathNode> pair = nodes.poll();
if(pair != null) {
long current = System.nanoTime();
pathfinder.search(path, pair.first(), pair.second());
paths.add(new LinkedList<PathNode>(path));
System.out.printf("Took %d nanoseconds\n", System.nanoTime() - current);
} else {
System.out.println("This cruncher is done");
break;
}
}
和单线程...
LinkedList<Pair<PathNode>> pairs = new LinkedList<Pair<PathNode>>();
int numPairs = 1000;
AStarPathfinder pathfinder = new AStarPathfinder(graph);
for(int i=0; i < numPairs; i++)
pairs.add(...);
for(int i=0; i < numPairs; i++) {
long current = System.nanoTime();
Pair<PathNode> pair = pairs.poll();
path.clear();
pathfinder.search(path, pair.first(), pair.second());
System.out.printf("Operation took %d nanoseconds", System.nanoTime() - current);
}
每个Cruncher都有自己的AStarPathfinder实例,因此pathfinder.search()无法在每个线程之间造成阻塞。多线程应用程序仍然慢得多。