Java:并快速进行排序通过多线程
-
26-09-2019 - |
题
我在尝试平行化算法。我开始合并排序,并发表我试图在这 的问题.我的订正试图在代码下面,我现在尝试并行快速进行排序。
是否有任何新的错误在我的多线程的执行或处理这个问题的方法?如果没有,我不应该预计超过32%的速度增加之间的顺序和并行的算法上的决心(见时在底部)?
这里是多线程的算法:
public class ThreadedQuick extends Thread
{
final int MAX_THREADS = Runtime.getRuntime().availableProcessors();
CountDownLatch doneSignal;
static int num_threads = 1;
int[] my_array;
int start, end;
public ThreadedQuick(CountDownLatch doneSignal, int[] array, int start, int end) {
this.my_array = array;
this.start = start;
this.end = end;
this.doneSignal = doneSignal;
}
public static void reset() {
num_threads = 1;
}
public void run() {
quicksort(my_array, start, end);
doneSignal.countDown();
num_threads--;
}
public void quicksort(int[] array, int start, int end) {
int len = end-start+1;
if (len <= 1)
return;
int pivot_index = medianOfThree(array, start, end);
int pivotValue = array[pivot_index];
swap(array, pivot_index, end);
int storeIndex = start;
for (int i = start; i < end; i++) {
if (array[i] <= pivotValue) {
swap(array, i, storeIndex);
storeIndex++;
}
}
swap(array, storeIndex, end);
if (num_threads < MAX_THREADS) {
num_threads++;
CountDownLatch completionSignal = new CountDownLatch(1);
new ThreadedQuick(completionSignal, array, start, storeIndex - 1).start();
quicksort(array, storeIndex + 1, end);
try {
completionSignal.await(1000, TimeUnit.SECONDS);
} catch(Exception ex) {
ex.printStackTrace();
}
} else {
quicksort(array, start, storeIndex - 1);
quicksort(array, storeIndex + 1, end);
}
}
}
这里是我开始:
ThreadedQuick.reset();
CountDownLatch completionSignal = new CountDownLatch(1);
new ThreadedQuick(completionSignal, array, 0, array.length-1).start();
try {
completionSignal.await(1000, TimeUnit.SECONDS);
} catch(Exception ex){
ex.printStackTrace();
}
我测试了这种对抗阵列。排序类似的顺序快速进行排序的算法。这里有时结果在一个英特尔对决核戴尔的笔记本电脑,在秒:
元素:500,000, 顺序:0.068592, 螺纹:0.046871, 阵列。排序:0.079677
元素:1,000,000的 顺序:0.14416, 螺纹:0.095492, 阵列。排序:0.167155
元素:2,000,000的, 顺序:0.301666, 螺纹:0.205719, 阵列。排序:0.350982
元素:4000000的, 顺序:0.623291, 螺纹:0.424119, 阵列。排序:0.712698
元素:大约为8 000 000, 顺序:1.279374, 螺纹:0.859363, 阵列。排序:1.487671
每个数字上的平均时间为100测试,投掷了3的最低和最高3的情况。我用随机的。nextInt(整数。MAX_VALUE)产生一系列对每一个测试,将其初始化时一次,每次10个测试,同的种子。每个测试包括时间给出的算法系统。nanoTime.我四舍五入到六个小数点后平均。显然,我有没有检查看看,如果每个排序 工作.
正如你可以看到,有大约32%的速度增加之间的顺序和螺纹的情况下在每一组试验。因为我问述,我不应该期望更多?
解决方案
制作numThreads静电可能会导致问题,它极有可能是你最终会比在某个点上运行max_threads的更多。
也许就是为什么你没有得到的性能了整整一倍,原因就在于你的快速排序不能完全并行化。请注意,以快速排序第一个电话会做一个穿过在初始线程整个阵列,它开始真正的并行运行之前。也有在养殖关闭以独立的线程时在上下文切换和模式转换的形式parallelising的算法的开销。
有一个看看fork / join框架,这个问题可能会十分吻合整齐地在那里。
上执行几个百分点。实现Runnable接口,而不是扩展Thread。延伸的线程应该在创建Thread类的一些新的版本才能使用。如果你只想做一些工作并行运行你最好用Runnable接口。虽然iplementing一个Runnable你也可以仍然扩展另一个类,让你在面向对象的设计更多的灵活性。使用仅限于您系统中可用的线程数线程池。也不要使用numThreads就是否叉掉一个新的线程与否的决定。您可以前计算这件事。使用最小分区大小是整个阵列由可用处理器的数量除以的大小。是这样的:
public class ThreadedQuick implements Runnable {
public static final int MAX_THREADS = Runtime.getRuntime().availableProcessors();
static final ExecutorService executor = Executors.newFixedThreadPool(MAX_THREADS);
final int[] my_array;
final int start, end;
private final int minParitionSize;
public ThreadedQuick(int minParitionSize, int[] array, int start, int end) {
this.minParitionSize = minParitionSize;
this.my_array = array;
this.start = start;
this.end = end;
}
public void run() {
quicksort(my_array, start, end);
}
public void quicksort(int[] array, int start, int end) {
int len = end - start + 1;
if (len <= 1)
return;
int pivot_index = medianOfThree(array, start, end);
int pivotValue = array[pivot_index];
swap(array, pivot_index, end);
int storeIndex = start;
for (int i = start; i < end; i++) {
if (array[i] <= pivotValue) {
swap(array, i, storeIndex);
storeIndex++;
}
}
swap(array, storeIndex, end);
if (len > minParitionSize) {
ThreadedQuick quick = new ThreadedQuick(minParitionSize, array, start, storeIndex - 1);
Future<?> future = executor.submit(quick);
quicksort(array, storeIndex + 1, end);
try {
future.get(1000, TimeUnit.SECONDS);
} catch (Exception ex) {
ex.printStackTrace();
}
} else {
quicksort(array, start, storeIndex - 1);
quicksort(array, storeIndex + 1, end);
}
}
}
您可以通过执行启动它:
ThreadedQuick quick = new ThreadedQuick(array / ThreadedQuick.MAX_THREADS, array, 0, array.length - 1);
quick.run();
这将启动排序在同一线程中,这避免了在启动时的不必要的螺纹一跳。
警告:。不知道上面的实施实际上将更快,因为我还没有基准它
其他提示
此用途快速排序和合并排序的组合。
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class ParallelSortMain {
public static void main(String... args) throws InterruptedException {
Random rand = new Random();
final int[] values = new int[100*1024*1024];
for (int i = 0; i < values.length; i++)
values[i] = rand.nextInt();
int threads = Runtime.getRuntime().availableProcessors();
ExecutorService es = Executors.newFixedThreadPool(threads);
int blockSize = (values.length + threads - 1) / threads;
for (int i = 0; i < values.length; i += blockSize) {
final int min = i;
final int max = Math.min(min + blockSize, values.length);
es.submit(new Runnable() {
@Override
public void run() {
Arrays.sort(values, min, max);
}
});
}
es.shutdown();
es.awaitTermination(10, TimeUnit.MINUTES);
for (int blockSize2 = blockSize; blockSize2 < values.length / 2; blockSize2 *= 2) {
for (int i = 0; i < values.length; i += blockSize2) {
final int min = i;
final int mid = Math.min(min + blockSize2, values.length);
final int max = Math.min(min + blockSize2 * 2, values.length);
mergeSort(values, min, mid, max);
}
}
}
private static boolean mergeSort(int[] values, int left, int mid, int end) {
int[] results = new int[end - left];
int l = left, r = mid, m = 0;
for (; l < left && r < mid; m++) {
int lv = values[l];
int rv = values[r];
if (lv < rv) {
results[m] = lv;
l++;
} else {
results[m] = rv;
r++;
}
}
while (l < mid)
results[m++] = values[l++];
while (r < end)
results[m++] = values[r++];
System.arraycopy(results, 0, values, left, results.length);
return false;
}
}
夫妻的意见,如果我理解你的代码的权利:
我没有看到一个锁绕numthreads对象虽然它可能是通过多线程。也许你应该让这一AtomicInteger.
使用一线的游泳池和安排的任务,即一个单一的呼吁快速排序,采取advantange的一线的游泳池。使用期货。
你的电流的分割方法的事情你们这么做可能会留下一个较小的司有线和一个较大的分工没有一线。这就是说,它并不优先考虑大部分他们自己的线。