4、串行程序并行化
考慮這樣一個(gè)問題:統(tǒng)計(jì)某個(gè)工程的代碼行數(shù)。首先想到的思路便是,遞歸文件樹,每層遞歸里,循環(huán)遍歷父文件夾下的所有子文件,如果子文件是文件夾,那么再對(duì)這個(gè)文件夾進(jìn)行遞歸調(diào)用。于是問題很輕松的解決了。這個(gè)方案可以優(yōu)化嗎??
再回想這個(gè)問題,可以發(fā)現(xiàn),循環(huán)里的遞歸調(diào)用其實(shí)相互之間是獨(dú)立的,互不干擾,各自統(tǒng)計(jì)自己路徑下的代碼文件的行數(shù)。于是,發(fā)現(xiàn)了這個(gè)方案的可優(yōu)化點(diǎn)——利用線程池進(jìn)行并行處理。于是一個(gè)串行的求解方案被改進(jìn)成了并行方案。
不能光說不練,寫了一個(gè)Demo,對(duì)串行方案和并行方案進(jìn)行了量化對(duì)比。代碼如下:
[java] view plain copyimport java.io.*;
import java.util.Queue;
import java.util.concurrent.*;
/**
* Created by cdlvsheng on 2016/5/16.
*/
public class ParallelSequentialContrast {
int coreSize = Runtime.getRuntime().availableProcessors();
ThreadPoolExecutor exec = new ThreadPoolExecutor(coreSize * 4, coreSize * 5, 0, TimeUnit.SECONDS,
new LinkedBlockingQueue《Runnable》(10000), new ThreadPoolExecutor.CallerRunsPolicy());
Queue《Future《Integer》》 queue = new ConcurrentLinkedQueue《Future《Integer》》();
private int countLineNum(File f) {
if (!f.getName().endsWith(“java”) && !f.getName().endsWith(“.js”) && !f.getName().endsWith(“.vm”)) return 0;
int sum = 0;
try {
BufferedReader br = new BufferedReader(new FileReader(f));
String str = null;
while ((str = br.readLine()) != null) sum++;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return sum;
}
private class Task implements Callable《Integer》 {
File f;
public Task(File f) {
this.f = f;
}
public Integer call() throws Exception {
int sum = 0;
if (f.isDirectory()) {
File[] fs = f.listFiles();
for (File file : fs) {
if (file.isDirectory()) queue.add(exec.submit(new Task(file)));
else sum += countLineNum(file);
}
} else sum += countLineNum(f);
return sum;
}
}
public int parallelTraverse(File f) {
queue.add(exec.submit(new Task(f)));
int sum = 0;
while (!queue.isEmpty()) {
try {
Future《Integer》 future = queue.poll();
sum += future.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
exec.shutdown();
return sum;
}
public int sequentialTraverse(File f) {
int sum = 0;
if (f.isDirectory()) {
File[] fs = f.listFiles();
for (File file : fs) {
if (file.isDirectory()) sum += sequentialTraverse(file);
else sum += countLineNum(file);
}
} else sum += countLineNum(f);
return sum;
}
public void parallelTest(ParallelSequentialContrast psc, String pathname) {
long start = System.currentTimeMillis();
int sum = psc.parallelTraverse(new File(pathname));
long duration = System.currentTimeMillis() - start;
System.out.println(String.format(“parallel test, %d lines of code were found, time cost is %d ms”, sum, duration));
}
public void sequentialTest(ParallelSequentialContrast psc, String pathname) {
long start = System.currentTimeMillis();
int sum = psc.sequentialTraverse(new File(pathname));
long duration = System.currentTimeMillis() - start;
System.out.println(String.format(“sequential test, %d lines of code were found, time cost is %d ms”, sum, duration));
}
public static void main(String[] args) {
ParallelSequentialContrast psc = new ParallelSequentialContrast();
String pathname = “D:\\Code_Git”;
psc.sequentialTest(psc, pathname);
psc.parallelTest(psc, pathname);
}
}
因?yàn)橐粩嗟膾叽疟P(雖然我的是固態(tài)硬盤),所以并行方案的線程池開的很大。IO密集型程序的相對(duì)CPU密集型程序的線程池會(huì)更大。
程序運(yùn)行結(jié)果如下:
?。踦lain] view plain copysequential test, 415079 lines of code were found, time cost is 364 ms
parallel test, 415079 lines of code were found, time cost is 163 ms
可以發(fā)現(xiàn),在結(jié)果同等精確的情況下,串行方案耗時(shí)是并行方案的兩倍多。這個(gè)是在我個(gè)人PC上做的測(cè)試,如果是線上服務(wù)器運(yùn)行,恐怕差距只會(huì)更加明顯。
如果一個(gè)大任務(wù),由許多個(gè)相互獨(dú)立的子任務(wù)組成,我們就可以在這里找突破點(diǎn),把一個(gè)串行程序并行化,榨干多和服務(wù)器的性能!
5、串行和并行的區(qū)別
串行通信是指 使用一條數(shù)據(jù)線,將數(shù)據(jù)一位一位地依次傳輸,每一位數(shù)據(jù)占據(jù)一個(gè)固定的時(shí)間長(zhǎng)度。其只需要少數(shù)幾條線就可以在系統(tǒng)間交換信息,特別使用于計(jì)算機(jī)與計(jì)算機(jī)、計(jì)算機(jī)與外設(shè)之間的遠(yuǎn)距離通信。終端與其他設(shè)備(例如其他終端、計(jì)算機(jī)和外部設(shè)備)通過數(shù)據(jù)傳輸進(jìn)行通信。數(shù)據(jù)傳輸可以通過兩種方式進(jìn)行:并行通信和串行通信。 在計(jì)算機(jī)和終端之間的數(shù)據(jù)傳輸通常是靠電纜或信道上的電流或電壓變化實(shí)現(xiàn)的。如果一組數(shù)據(jù)的各數(shù)據(jù)位在多條線上同時(shí)被傳輸,這種傳輸方式稱為并行通信。 并行通信時(shí)數(shù)據(jù)的各個(gè)位同時(shí)傳送,可以字或字節(jié)為單位并行進(jìn)行。并行通信速度快,但用的通信線多、成本高,故不宜進(jìn)行遠(yuǎn)距離通信。計(jì)算機(jī)或plc各種內(nèi)部總線就是以并行方式傳送數(shù)據(jù)的。另外,在PLC底板上,各種模塊之間通過底板總線交換數(shù)據(jù)也以并行方式進(jìn)行。
并行通信傳輸中有多個(gè)數(shù)據(jù)位,同時(shí)在兩個(gè)設(shè)備之間傳輸。發(fā)送設(shè)備將這些數(shù)據(jù)位通過 對(duì)應(yīng)的數(shù)據(jù)線傳送給接收設(shè)備,還可附加一位數(shù)據(jù)校驗(yàn)位。接收設(shè)備可同時(shí)接收到這些數(shù)據(jù),不需要做任何變換就可直接使用。并行方式主要用于近距離通信。計(jì)算 機(jī)內(nèi)的總線結(jié)構(gòu)就是并行通信的例子。這種方法的優(yōu)點(diǎn)是傳輸速度快,處理簡(jiǎn)單。
串行數(shù)據(jù)傳輸時(shí),數(shù)據(jù)是一位一位地在通信線上傳輸?shù)模扔删哂袔孜豢偩€的計(jì)算機(jī)內(nèi)的發(fā)送設(shè)備,將幾位并行數(shù)據(jù)經(jīng)并--串轉(zhuǎn)換硬件轉(zhuǎn)換成串行方式,再逐位經(jīng) 傳輸線到達(dá)接收站的設(shè)備中,并在接收端將數(shù)據(jù)從串行方式重新轉(zhuǎn)換成并行方式,以供接收方使用。串行數(shù)據(jù)傳輸?shù)乃俣纫炔⑿袀鬏斅枚?,但?duì)于覆蓋面極其廣 闊的公用電話系統(tǒng)來說具有更大的現(xiàn)實(shí)意義。
串行數(shù)據(jù)通信的方向性結(jié)構(gòu)有三種,即單工、半雙工和全雙工。
評(píng)論
查看更多