概论
在传统的串行运行下,在数组内查找特定元素和将数组排序都有一套成熟的方法。
对于数组内查找,如果是有序数组在可以在查找的话可以运用二分查找法,而对于无序数组则应该将数组遍历一遍。
而对于数组排序,则是有类似快排,归并排序等等复杂度控制在O(nlogn)的算法。
从算法的角度来说,似乎并没有往下继续优化的空间了。但是如果运行在并行环境下,虽然理论上的算法复杂度并没有变小,但是我们可以用并行的方式来将时间缩短。
为何可以使用并行
考虑这么一件事情,如果我们将一堆苹果放在一个篮子里,那么我们唯一能做的做法就是将苹果一个个的依次放入篮子,这没什么好说的。那么如果我们要加快速度的话,我们会多派一个人手,比如将苹果堆一分为二,然后两个人分别将两堆苹果同时放到一个篮子里。但是如果我们考虑到我们希望放入苹果时,希望是一个红苹果一个青苹果间隔,那么在两个人毫无配合的情况下,这种方式反而不如一个人依次放入来的效果好。也就是说,运用并行的场景下,要求我们所处理的数据互相不干扰,那么你就可以使用并行来充分的利用起时间。
数组并行搜索
对于一个数组,我们想在里面找到元素a的下标,在串行模式中我们只能运用遍历的方式来搜索指定元素。但是如果我们将数组一分为二,然后将分配两个线程并行的单独搜索,那么CPU也就被更多的利用了。
以Java为例子,首先我们准备好线程池,并发数,原子性的Int与数组
static ExecutorService pool = Executors.newCachedThreadPool();
static final int Thread_Num = 2;
static AtomicInteger res = new AtomicInteger(-1);
static int[] arr;
然后我们在再编写每个线程所应该执行的搜索函数,规定了搜索值与搜索区间
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static int search(int searchValue,int beginPos,int endPos){
for(int i = beginPos;i<endPos;i++){
if(res.get()>=0){
return res.get();
}
if(arr[i] == searchValue){
System.out.println("Found");
if( !res.compareAndSet(-1,i)){
return res.get();
}
return i;
}
}
return -1;
}
然后我们创建每个线程完成的任务,以Future模式声明,实现了Callable接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static class SearchTask implements Callable<Integer>{
int begin,end,searchValue;
public SearchTask(int begin, int end, int searchValue) {
this.begin = begin;
this.end = end;
this.searchValue = searchValue;
}
public Integer call() throws Exception {
int re = search(searchValue,begin,end);
return re;
}
}
最好我们将搜索封装成一个函数即可,当中由于一个数组被切割成N份来并行搜索,我们可以用Arraylist来包装每个线程,从而遍历每个线程是否得到结果。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public static int pSearch(int searchValue) throws ExecutionException, InterruptedException {
int subArrSize = arr.length/Thread_Num+1;
List<Future<Integer>> re = new ArrayList<Future<Integer>>();
for(int i = 0;i<arr.length;i++){
int end = i +subArrSize;
if(end>=arr.length){
end = arr.length;
}
re.add(pool.submit(new SearchTask(i,end,searchValue)));
}
try {
for (Future<Integer> fu : re) {
if (fu.get() >= 0) {
return fu.get();
}
}
return -1;
}finally {
pool.shutdown();
}
}
最后
许多串行情境下的算法,只要当中数据不相互影响,大部分都可以用并发的情境来充分利用CPU,下次我会分析下如何使用并发来数组排序