我尝试parallelize
我的merge sort实施:http://pastebin.com/2uMGjTxr。
我想创建Java-VM可以提供的线程数。我想使用 java.lang.Runtime 确定可能的最大线程数。
所以我想出了一个名为MergeThread的类:
public class MergeThread implements Runnable{
public int[] list;
int sIndex, eIndex;
public MergeThread(int[] pArray, int pStartIndex, int pEndIndex){
list = pArray;
sIndex = pStartIndex;
eIndex = pEndIndex;
}
public void run(){
list = mergeSort(list, sIndex, eIndex);
}
/**
* Merges two sorted int array into one new sorted array.
* @param lhs
* @param rhs
* @return
*/
private static int[] merge(int[] lhs, int[] rhs) {
int[] result = new int[lhs.length + rhs.length];
int leftIndex = 0;
int rightIndex = 0;
while(leftIndex < lhs.length && rightIndex < rhs.length) {
if(lhs[leftIndex] <= rhs[rightIndex]) {
result[leftIndex + rightIndex] = lhs[leftIndex];
leftIndex++;
} else {
result[leftIndex + rightIndex] = rhs[rightIndex];
rightIndex++;
}
}
while(leftIndex < lhs.length) {
result[leftIndex + rightIndex] = lhs[leftIndex];
leftIndex++;
}
while(rightIndex < rhs.length) {
result[leftIndex + rightIndex] = rhs[rightIndex];
rightIndex++;
}
return result;
}
/**
* Sorts an array from index <code>startIndex</code> (inclusive) to <code>endIndex</code> (exclusive).
* @param array
* @param startIndex
* @param endIndex
* @return new array that is sorted
*/
private static int[] mergeSort(int[] array, int startIndex, int endIndex) {
int length = endIndex - startIndex;
if(length == 0) {
return new int[]{};
}
if(length == 1) {
return new int[]{array[startIndex]};
}
int halfLength = length / 2;
//int[] sortedLeftPart = mergeSort(array, startIndex, startIndex + halfLength);
MergeThread m1 = new MergeThread(array, startIndex, startIndex + halfLength);
Thread t1 = new Thread(m1);
t1.start();
//int[] sortedRightPart = mergeSort(array, startIndex + halfLength, endIndex);
MergeThread m2 = new MergeThread(array, startIndex + halfLength, endIndex);
Thread t2 = new Thread(m2);
t2.start();
try{
t1.join();
t2.join();
}catch(InterruptedException e){}
return merge(m1.list, m2.list);
}
}
实际开始这个过程的课程
import java.util.Random;
public class Aufg2 {
public static Random random = new Random(100);
public static void main(String[] args) {
int[] array = createRandomArray(10000000);
long time = System.currentTimeMillis();
int[] sortedArray = sort(array);
if(sortedArray.length != array.length || !isSorted(sortedArray)) {
System.err.println("Failed to sort given array! :-(");
return;
}
System.out.println("Success! Sorting took " + (System.currentTimeMillis() - time) + "ms.");
}
/**
* Creates a randomly filled array of given length
* @param length
* @return
*/
private static int[] createRandomArray(int length) {
int[] result = new int[length];
for(int i = 0; i < length; i++) {
result[i] = random.nextInt();
}
return result;
}
/**
* Checks whether a given int array is sorted in ascending order
* @param array
* @return <code>true</code> if the given int array is sorted; <code>false</code> otherwise.
*/
private static boolean isSorted(int[] array) {
for(int i = 1; i < array.length; i++) {
if(array[i] < array[i-1]) {
return false;
}
}
return true;
}
/**
* Sorts a given array (ascending order)
* @param array
* @return
*/
private static int[] sort(int[] array){
//TODO: use multiple threads to speed up the sorting
MergeThread m = new MergeThread(array, 0, array.length);
try{
Thread t1 = new Thread(m);
t1.start();
t1.join();
}catch(InterruptedException e){
}
return m.list;
}
}
但是这种合并排序不起作用。控制台会打印很多java.lang.OutOfMemmoryError's unable to create new native thread
。
稍后消息会更改为java heap
。
我需要更改什么才能使合并排序正常工作?如何使用java.lang.Runtime?
答案 0 :(得分:6)
分而治之的机制让你尝试创建类似5000000个线程的东西 - 并且每个线程都需要默认的256KB(IIRC)堆栈内存。仍然感到惊讶,为什么你得到OutOfMemmoryError
?
使用fixed size thread pool限制线程数 - 尝试使用池中的线程数,但是远远超过系统中核心数的任何东西都不太可能提高性能(并且可能确实减少它。)
答案 1 :(得分:1)
首先使用ExecutorService并在其中排队新任务,而不是创建数百万个线程(这应该摆脱第一个问题;如果创建数百万个线程,迟早会耗尽资源)。核心数量的1.5倍通常是一个很好的猜测(通常比使用可用核心数量更好的结果 - 但这是你必须要玩的东西)。
然后 - 如果您希望此算法在任何性能上都非常重要 - 在合理的阈值下使用QuickSort表示叶子情况,或者如果您想要较低的阈值则使用InsertionSort(如果使用Insertion Sort,则将叶子节点大小设置为16或者工作得很好。
答案 2 :(得分:0)
让一个线程执行数组的后半部分,而调用线程处理前半部分
int halfLength = length / 2;
MergeThread m2 = new MergeThread(array, startIndex + halfLength, endIndex);
Thread t2 = new Thread(m2);
t2.start();//let new thread handle the second half
array = mergeSort(array, startIndex, startIndex + halfLength);//do first half ourselves
try{
t2.join();
}catch(InterruptedException e){}
return merge(array, m2.list);
这减少了创建的线程数量减少了一半
但快速排序更好地并行化,因为它不需要一个后递归步骤,允许线程(具有执行程序的可运行作业)在委派后立即返回
然后,呼叫者只需要注意所有工作何时完成