Java 从并发过渡到并行处理
我有一个四核cpu,出于性能原因,我一直在尝试多线程。我在下面编写了这段代码,只是想看看它的速度有多快,我注意到它实际上比只使用主线程的第二个代码块慢Java 从并发过渡到并行处理,java,multithreading,Java,Multithreading,我有一个四核cpu,出于性能原因,我一直在尝试多线程。我在下面编写了这段代码,只是想看看它的速度有多快,我注意到它实际上比只使用主线程的第二个代码块慢 int numCrunchers = Runtime.getRuntime().availableProcessors(); public void crunch() { int numPairs = 1000; for(int i=0; i < numPairs; i++) pairs.add(...);
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;
}
}
}
}
int numCrunchers=Runtime.getRuntime().availableProcessors();
公共空间紧缩{
int numPairs=1000;
for(int i=0;i
在我的电脑上,每个线程大约需要340000000000纳秒,但当我决定除了主线程之外不使用任何线程时,只需要1090195046纳秒,时间差为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);
LinkedList pairs=新建LinkedList();
int numPairs=1000;
AStarPathfinder pathfinder=新的AStarPathfinder(图形);
for(int i=0;i
我的问题是为什么使用多线程会导致程序运行缓慢?代码是否没有正确地利用我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;
}
}
while(true){
path.clear();
Pair Pair=nodes.poll();
如果(对!=null){
长电流=System.nanoTime();
搜索(路径,pair.first(),pair.second());
添加(新链接列表(路径));
System.out.printf(“花费了%d纳秒\n”,System.nanoTime()-当前值);
}否则{
System.out.println(“这个紧缩器完成了”);
打破
}
}
和单线程
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);
}
LinkedList pairs=新建LinkedList();
int numPairs=1000;
AStarPathfinder pathfinder=新的AStarPathfinder(图形);
for(int i=0;i
每个Cruncher都有自己的AStarPathfinder实例,因此pathfinder.search()不能在每个线程之间造成阻塞。多线程应用程序仍然慢得多。这可能是由于多种原因造成的。创建和启动线程非常昂贵。线程之间的上下文切换也增加了这一点。尝试做一些需要几毫秒的事情。你也许会看到一些不同。尝试执行一个需要几秒钟时间的操作(在主线程上),您将(很可能)看到2代码块的性能发生了巨大变化。我将numPairs值更改为5000,并测量了每个cruncher内每次搜索所用的时间。这就是我发现的。在多线程应用程序上的每次搜索大约需要123235110到153037850纳秒,而在单线程应用程序上,最长的操作是2564662纳秒。向线程添加更多的工作似乎没有多大作用,而且似乎每个线程都共享一个核心。我想,仅仅创建线程(如上所述,成本很高)并将数据复制到线程(创建线程时串行执行)需要花费大量时间。由于咀嚼本身似乎不需要花费太多时间,因此执行750次甚至3750次额外的咀嚼仍然比所有的复制要短得多