【问题标题】:Why is my threaded sort algorithm slow compared to the non-threaded version?为什么我的线程排序算法比非线程版本慢?
【发布时间】:2011-05-07 22:49:44
【问题描述】:

我刚刚实现了合并排序的线程版本。 ThreadedMerge.java:http://pastebin.com/5ZEvU6BV

由于合并排序是一种分而治之的算法,我为数组的每一半创建一个线程。但是 Java-VM 中可用线程的数量是有限的,所以我在创建线程之前检查一下:

if(num <= nrOfProcessors){
    num += 2;
   //create more threads
}else{
   //continue without threading
}

但是,线程排序大约需要 ~ 6000 ms,而非线程版本只需 ~ 2500 ms 就快得多。

非线程:http://pastebin.com/7FdhZ4Fw

为什么线程版本较慢,我该如何解决这个问题?


更新:我现在使用atomic integer 进行线程计数,并为Runtime.getRuntime().availableProcessors() 声明了一个静态字段。现在排序大约需要~ 1400 ms。

但是,在 mergeSort 方法中只创建一个线程并让当前线程完成其余的工作并没有显着的性能提升。 为什么?

除了当我在一个线程上调用 join 之后减少使用的线程数

num.set(num.intValue() - 1);

排序大约需要~ 200 ms 更长的时间。这里是我算法的更新http://pastebin.com/NTZq5zQp为什么这行代码会更糟?

【问题讨论】:

  • 我不知道你的数据,但对于小型数组,创建线程的开销很容易超过并行收益。另外,你知道线程是否真的在不同的处理器中?

标签: java multithreading


【解决方案1】:

首先你对 num 的访问不是线程安全的(检查 http://download.oracle.com/javase/6/docs/api/java/util/concurrent/atomic/AtomicInteger.html )

您为核心创建了相同数量的进程,但您通过加入调用阻止了其中的一半

num += 1;
ThreadedMerge tm1 = new ThreadedMerge(array, startIndex, startIndex + halfLength);
tm1.start();
sortedRightPart = mergeSort(array, startIndex + halfLength, endIndex);
try{
    tm1.join(); 
    num-=1
    sortedLeftPart = tm1.list;
}catch(InterruptedException e){
}

这不会阻塞调用线程,而是使用它来对正确的部分进行排序,并让创建的线程在返回时执行另一部分,它占用的空间可以被另一个线程使用

【讨论】:

    【解决方案2】:

    嗯,你不应该为每一步都创建一个线程(它们很昂贵,并且有轻量级的替代方案。)

    理想情况下,如果有 4 个 CPU,您应该只创建 4 个线程。

    假设你有 4 个 CPU,然后你在第一级创建一个线程(现在你有 2 个),在第二级你还创建一个新线程。这给了你 4 个。

    你只创建一个而不创建两个的原因是你可以使用你当前正在运行的线程:

    Thread t = new Thread(...);
    t.start();
    
    // Do half of the job here
    
    t.join(); // Wait for the other half to complete.
    

    如果您有 5 个 CPU(不是两个的幂),那么只需创建 8 个线程。

    在实践中执行此操作的一种简单方法是在达到适当级别时创建您已经制作的非线程版本。这样可以避免在 if 语句等时混淆合并方法。

    【讨论】:

    • 把你的代码分成两部分:) 一个做实际的排序,一个启动线程。那会容易很多。在我的笔记本电脑(双核)上,您的代码启动了 4 个线程,因此处理线程时有些问题。
    • 我只是将最大数量设置为 4,与创建 1000 个线程相比,性能没有改变:D。为什么不拥有这 1000 个线程,并以相同的方式为每个线程划分整个计算工作?
    • @ArtWorkAD 不,因为您的代码存在根本性的问题。我不确定你的意思,但创建 1000 个线程是一个非常糟糕的主意 - 创建 1000 个操作系统线程需要很长时间。
    【解决方案3】:

    拨打Runtime.availableProcessors() 似乎占用了相当多的额外时间。您只需要调用一次,因此只需将其移出方法并将其定义为静态,例如:

    static int nrOfProcessors = Runtime.getRuntime().availableProcessors();
    

    【讨论】:

      猜你喜欢
      • 2015-08-21
      • 1970-01-01
      • 2011-02-22
      • 1970-01-01
      • 2015-07-09
      • 2017-12-26
      • 2014-07-21
      • 2011-03-01
      • 2015-08-22
      相关资源
      最近更新 更多