【问题标题】:How to ensure Java threads run on different cores如何确保 Java 线程在不同的内核上运行
【发布时间】:2010-12-26 03:32:19
【问题描述】:

我正在用 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 变量。因此,除了最后那个小的关键部分之外,每个线程几乎都应该完全并行执行。

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

有人有什么见解吗?

【问题讨论】:

  • 欢迎来到并行计算的世界!您的线程很可能实际上被映射到不同的内核,并且如果它们位于同一内核上,您的程序实际上可能会更快(尽管仍然比顺序版本慢)。你从哪里得到并行背包算法?是否旨在尽可能减少共享内存通信(包括锁定)?
  • 如果您发布一个指向您的 KnapsackThread 代码的链接,并说明您正在使用的线程数量,这可能会很有用。多于 4-8 个线程可能是一个核心双核的问题,同步块可以降低任何代码:)
  • 你还用什么VM,windows上的sun和ubuntu上的openjdk,还是两者都用sun?
  • 我从另一个人的顺序版本编写了我的版本。它不会锁定对共享二维数组的访问,但我确实确保每个线程只写入二维数组的不同索引以避免竞争条件。我每个核心使用一个线程,我这样做: private static KnapsackThread threads[] = new KnapsackThread[ Runtime.getRuntime().availableProcessors() ]; }
  • 我不知道除了 1.6 之外我使用的是什么 VM。我在终端中运行了 java -version:java version "1.6.0_16" Java(TM) SE Runtime Environment (build 1.6.0_16-b01) Java HotSpot(TM) Server VM (build 14.2-b01, mixed mode)跨度>

标签: java multithreading multicore knapsack-problem


【解决方案1】:

我怀疑这是因为所有线程都使用相同的内核。调度取决于操作系统,但如果您调出操作系统的性能管理器,您应该能够看到发生了什么 - 它通常会显示每个内核的繁忙程度。

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

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

【讨论】:

  • 很好的答案,像往常一样。但是我怀疑我们可以排除您的第二个要点:查看编码,显然正在创建少量线程,并且这些线程运行一次-很长一段时间。同步看起来是个不错的选择。
  • @Carl:我们还没有真正看到足够多的代码来知道。我们不知道threads 数组有多大,除非我遗漏了什么。
  • Runtime.availablePrcoessors 会给出硬件线程的数量。)
  • Runtine.availableProcessors 给了我核心数量对吗?不是线程
  • 正如方法名称已经暗示的那样,它返回可用处理器的数量(逻辑处理单元、CPU 核心,如您所愿),而不是线程。
【解决方案2】:

我建议您查看每个工作线程在终止之前需要多长时间。也许其中一个线程的任务要困难得多。如果是这样的话,那么同步等所造成的开销很容易会吃掉你从线程中获得的东西。

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • 哇,谢谢我在做基准测试,想知道为什么基准测试只使用 7 个核心中的 2 个。增加堆空间为我解决了这个问题!
    猜你喜欢
    • 1970-01-01
    • 2013-02-01
    • 2013-02-27
    • 2018-05-29
    • 1970-01-01
    • 2011-11-24
    • 1970-01-01
    • 2013-07-13
    • 2017-08-22
    相关资源
    最近更新 更多