如何确保Java线程在不同的核心上运行

时间:2009-12-13 10:05:09

标签: java multithreading multicore knapsack-problem

我正在用Java编写一个多线程应用程序,以提高顺序版本的性能。它是0/1背包问题的动态编程解决方案的并行版本。我有一个Intel Core 2 Duo,在不同的分区上同时使用Ubuntu和Windows 7 Professional。我在Ubuntu中运行。

我的问题是并行版本实际上需要比顺序版本更长的时间。我想这可能是因为线程都被映射到同一个内核线程或者它们被分配到同一个内核。有没有办法确保每个Java线程映射到一个单独的核心?

我已阅读有关此问题的其他帖子,但似乎没有任何帮助。

这是KnapsackThread类(扩展Thread)的main()和run()的结束。请注意,我使用slice和extra来计算myLowBound,myHiBound确保每个线程不会在dynProgMatrix的域中重叠。因此没有竞争条件。

    dynProgMatrix = new int[totalItems+1][capacity+1];
    for (int w = 0; w<= capacity; w++)
        dynProgMatrix[0][w] = 0;
    for(int i=0; i<=totalItems; i++)
        dynProgMatrix[i][0] = 0;
    slice = Math.max(1,
            (int) Math.floor((double)(dynProgMatrix[0].length)/threads.length));
    extra = (dynProgMatrix[0].length) % threads.length;

    barrier = new CyclicBarrier(threads.length);
    for (int i = 0; i <  threads.length; i++){
        threads[i] = new KnapsackThread(Integer.toString(i));
    }
    for (int i = 0; i < threads.length; i++){
        threads[i].start();
    }

    for (int i = 0; i < threads.length; i++){
        try {
            threads[i].join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public void run(){
    int myRank = Integer.parseInt(this.getName());

    int myLowBound;
    int myHiBound;

    if (myRank < extra){
        myLowBound = myRank * (slice + 1);
        myHiBound = myLowBound + slice;
    }
    else{
        myLowBound = myRank * slice + extra;
        myHiBound = myLowBound + slice - 1;
    }

    if(myHiBound > capacity){
        myHiBound = capacity;
    }

    for(int i = 1; i <= totalItems; i++){
        for (int w = myLowBound; w <= myHiBound; w++){

            if (allItems[i].weight <= w){
               if (allItems[i].profit + dynProgMatrix[i-1][w-allItems[i].weight]
                        > dynProgMatrix[i-1][w])
                {
                    dynProgMatrix[i][w] = allItems[i].profit +
                                      dynProgMatrix[i-1][w- allItems[i].weight];
                }
                else{
                    dynProgMatrix[i][w] = dynProgMatrix[i-1][w];
                }
            }
            else{
                dynProgMatrix[i][w] = dynProgMatrix[i-1][w];
            }
        }
        // now place a barrier to sync up the threads
        try {
            barrier.await(); 
        } catch (InterruptedException ex) { 
            ex.printStackTrace();
            return;
        } catch (BrokenBarrierException ex) { 
            ex.printStackTrace(); 
            return;
        }
    }
}

更新

我写过另一个使用蛮力的背包版本。这个版本的同步很少,因为我只需要在单个线程的执行结束时更新bestSoFar变量。因此,每个线程几乎应该完全并行执行,除了最后那个小的关键部分。

我对此顺序蛮力运行,但仍然需要更长时间。我没有看到任何其他解释,因为我的线程是按顺序运行的,因为它们被映射到同一个核心或同一个本机线程。

有人有任何见解吗?

3 个答案:

答案 0 :(得分:20)

我怀疑这是因为所有线程使用相同的核心。调度由操作系统决定,但如果您启动操作系统的性能管理器,您应该能够看到正在发生的事情 - 它通常会显示每个内核的繁忙程度。

可能需要更长时间的原因:

  • 大量同步(必要或不必要)
  • 任务花费如此短的时间以至于线程创建占用了相当大的时间
  • 上下文切换,如果您创建的线程太多 - 对于CPU密集型任务,请创建与核心一样多的线程。

答案 1 :(得分:6)

我有一段时间遇到同样的问题。我有一个CPU饥饿的程序,我分为2个线程(双核CPU),但一个美好的一天,处理更多的数据,它只是停止使用两个核心。我刚刚提高了堆内存大小(在我的情况下为-Xmx1536m),它再次正常工作。

答案 2 :(得分:1)

我建议你看一下你的每个工作线程在终止之前需要多长时间。也许其中一个线程有一个更困难的任务。如果是这种情况,那么由同步等引起的开销很容易就会消​​耗掉你从线程中获得的开销。