为了追求学习,我编写了一个多线程线性搜索,旨在对int []数组进行操作。我相信搜索可以按预期进行,但是在完成搜索后,我针对标准的“ for循环”进行了测试,并惊讶地发现“ for循环”每次都在速度方面胜过我的搜索。我尝试修改代码,但无法获得击败基本“ for循环”的搜索。目前,我想知道以下内容:
我的代码中是否存在明显的漏洞?
我的代码是否可能没有针对CPU缓存进行优化?
难道这仅仅是多线程的开销,减慢了我的程序的速度,所以我需要更大的数组才能获得好处?
我自己无法解决,我希望这里的某人能够指出正确的方向,从而引发我的问题:
我的代码中是否存在效率/缺陷使其比标准循环慢的速度,还是仅仅是线程的开销使速度降低了?
搜索:
public class MLinearSearch {
private MLinearSearch() {};
public static int[] getMultithreadingPositions(int[] data, int processors) {
int pieceSize = data.length / processors;
int remainder = data.length % processors;
int curPosition = 0;
int[] results = new int[processors + 1];
for (int i = 0; i < results.length - 1; i++) {
results[i] = curPosition;
curPosition += pieceSize;
if(i < remainder) {
curPosition++;
}
}
results[results.length - 1] = data.length;
return results;
}
public static int search(int target, int[]data) {
MLinearSearch.processors = Runtime.getRuntime().availableProcessors();
MLinearSearch.foundIndex = -1;
int[] domains = MLinearSearch.getMultithreadingPositions(data, processors);
Thread[] threads = new Thread[MLinearSearch.processors];
for(int i = 0; i < MLinearSearch.processors; i++) {
MLSThread searcher = new MLSThread(target, data, domains[i], domains[(i + 1)]);
searcher.setDaemon(true);
threads[i] = searcher;
searcher.run();
}
for(Thread thread : threads) {
try {
thread.join();
} catch (InterruptedException e) {
return MLinearSearch.foundIndex;
}
}
return MLinearSearch.foundIndex;
}
private static class MLSThread extends Thread {
private MLSThread(int target, int[] data, int start, int end) {
this.counter = start;
this.dataEnd = end;
this.target = target;
this.data = data;
}
@Override
public void run() {
while(this.counter < (this.dataEnd) && MLinearSearch.foundIndex == -1) {
if(this.target == this.data[this.counter]) {
MLinearSearch.foundIndex = this.counter;
return;
}
counter++;
}
}
private int counter;
private int dataEnd;
private int target;
private int[] data;
}
private static volatile int foundIndex = -1;
private static volatile int processors;
}
注意:“ getMultithreadingPositions”通常在单独的类中。为了简单起见,我在这里复制了该方法。
这就是我一直在测试代码的方式。另一项测试(此处省略,但在同一文件中并运行)运行了基本的for循环,每次都击败了我的多线程搜索。
public class SearchingTest {
@Test
public void multiLinearTest() {
int index = MLinearSearch.search(TARGET, arrayData);
assertEquals(TARGET, arrayData[index]);
}
private static int[] getShuffledArray(int[] array) {
// https://stackoverflow.com/questions/1519736/random-shuffling-of-an-array
Random rnd = ThreadLocalRandom.current();
for (int i = array.length - 1; i > 0; i--)
{
int index = rnd.nextInt(i + 1);
int a = array[index];
array[index] = array[i];
array[i] = a;
}
return array;
}
private static final int[] arrayData = SearchingTests.getShuffledArray(IntStream.range(0, 55_000_000).toArray());
private static final int TARGET = 7;
}
击败它的循环实际上只是在相同数组上迭代的for循环。我可以想象对于较小的数组,for循环将胜出,因为它的简单性使其可以在我的多线程搜索可以启动其线程之前开始运行。在阵列大小的情况下,尽管我原本希望有一个线程丢失,但我仍在尝试。
注意:我必须使用以下JVM参数来增加堆大小:
-Xmx4096m
为避免堆内存异常。
感谢您提供的任何帮助。