为什么我的线程排序算法比非线程版本慢?

发布于 2024-11-05 20:43:20 字数 1086 浏览 0 评论 0原文

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

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

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

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

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

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


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

然而,在 mergeSort 方法中仅创建一个线程并让当前线程执行其余操作并不会显着提高性能。 为什么?

减少使用的线程数,

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

此外,当我在线程上调用 join 之后,然后通过排序 需要大约 ~ 200 ms 更长的时间。这是我的算法的更新 http://pastebin.com/NTZq5zQp 为什么这行代码使它均匀更糟?

I just have implemented a threaded version of the merge sort. ThreadedMerge.java: http://pastebin.com/5ZEvU6BV

Since merge sort is a divide and conquer algorithm I create a thread for every half of the array. But the number of avialable threads in Java-VM is limited so I check that before creating threads:

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

However the threaded sorting takes about ~ 6000 ms while the non-threaded version is much faster with just ~ 2500 ms.

Non-Threaded: http://pastebin.com/7FdhZ4Fw

Why is the threaded version slower and how do I solve that problem?


Update: I use atomic integer now for thread counting and declared a static field for Runtime.getRuntime().availableProcessors(). The sorting takes about ~ 1400 ms now.

However creating just one thread in the mergeSort method and let the current thread do the rest has no sigificant performance increase. Why?

Besides when after I call join on a thread and after that decrement the number of used threads with

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

the sorting takes about ~ 200 ms longer. Here is the update of my algorithm http://pastebin.com/NTZq5zQp Why does this line of code make it even worse?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

爱殇璃 2024-11-12 20:43:20

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

您创建了与核心相同数量的进程,但您阻止了其中一半使用 join 调用,

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){
}

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

first off your accesses to num is not threadsafe (check http://download.oracle.com/javase/6/docs/api/java/util/concurrent/atomic/AtomicInteger.html )

you create an equal amount of processes to cores but you block half of them with the join call

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){
}

this doesn't block the calling thread but uses it to sort the right part and let the created thread do the other part when that one returns the space it takes up can be used by another thread

银河中√捞星星 2024-11-12 20:43:20

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

理想情况下,如果有 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(不是 2 的幂),那么只需创建8个线程。

在实践中执行此操作的一种简单方法是,当您达到适当的级别时,创建您已经制作的无线程版本。通过这种方式,您可以避免在使用 if 语句等时使合并方法变得混乱。

Hhm, you should not create a thread for every single step (they are expensive and there are lightweight alternatives.)

Ideally, you should only create 4 threads if there are 4 CPU´s.

So let´s say you have 4 CPU´s, then you create one thread at the first level (now you have 2) and at the second level you also create a new thread. This gives you 4.

The reason why you only create one and not two is that you can use the thread you are currently running like:

Thread t = new Thread(...);
t.start();

// Do half of the job here

t.join(); // Wait for the other half to complete.

If you have, let´s say, 5 CPU´s (not in the power of two) then just create 8 threads.

One simple way to do this in practice, is to create the un-threaded version you already made when you reach the appropriate level. In this way you avoid to clutter the merge method when if-sentences etc.

望笑 2024-11-12 20:43:20

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

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

The call to Runtime.availableProcessors() appears to be taking up a fair amount of extra time. You only need to call it once, so just move it outside of the method and define it as a static, e.g.:

static int nrOfProcessors = Runtime.getRuntime().availableProcessors();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文