Java 中的並行處理
1. 背景
本文是一個短文章,介紹Java 中的並行處理。
說明:10多分鐘讀完的文章我稱之為短文章,適合快速閱讀。
2.知識
平行計算(parallel computing)一般是指許多指令得以同時進行的計算模式。在同時進行的前提下,可以將計算的過程分解成小部分,之後以併發方式來加以解決。
也就是分解為幾個過程:
1、將一個大任務拆分成多個子任務,子任務還可以繼續拆分。
2、各個子任務同時進行運算執行。
3、在執行完畢後,可能會有個 " 歸納 " 的任務,比如 求和,求平均等。
再簡化一點的理解就是: 先拆分 --> 在同時進行計算 --> 最後“歸納”
為什麼要“並行”,優點呢?
1、為了獲得 “節省時間”,“快”。適合用於大規模運算的場景。從理論上講,在 n 個並行處理的執行速度可能會是在單一處理機上執行的速度的 n 倍。
2、以前的計算機是單核的,現代的計算機Cpu都是多核的,伺服器甚至都是多Cpu的,平行計算可以充分利用硬體的效能。
3. Java 中的並行處理
JDK 8 新增的Stream API(java.util.stream)將生成環境的函數語言程式設計引入了Java庫中,可以方便開發者能夠寫出更加有效、更加簡潔的程式碼。
steam 的另一個價值是創造性地支援並行處理(parallel processing)。示例:
final Collection tasks = Arrays.asList(
new Task( Status.OPEN, 5 ),
new Task( Status.OPEN, 13 ),
new Task( Status.CLOSED, 8 )
);
// 並行執行多個任務,並 求和
final double totalPoints = tasks
.stream()
.parallel()
.map( task -> task.getPoints() ) // or map( Task::getPoints )
.reduce( 0, Integer::sum );
System.out.println( "Total points (all tasks): " + totalPoints );
4. 擴充套件
執行緒池方式實現並行處理
jdk1.5引入了併發包,其中包括了ThreadPoolExecutor,相關程式碼如下:
public class ExecutorServiceTest {
public static final int THRESHOLD = 10_000;
public static long[] numbers;
public static void main(String[] args) throws Exception {
numbers = LongStream.rangeClosed(1, 10_000_000).toArray();
ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() + 1);
CompletionService
int taskSize = (int) (numbers.length / THRESHOLD);
for (int i = 1; i
final int key = i;
completionService.submit(new Callable
@Override
public Long call() throws Exception {
return sum((key - 1) * THRESHOLD, key * THRESHOLD);
}
});
}
long sumValue = 0;
for (int i = 0; i
sumValue += completionService.take().get();
}
// 所有任務已經完成,關閉執行緒池
System.out.println("sumValue = " + sumValue);
executor.shutdown();
}
private static long sum(int start, int end) {
long sum = 0;
for (int i = start; i
sum += numbers[i];
}
return sum;
}
}
public class ExecutorServiceTest {
public static final int THRESHOLD = 10_000;
public static long[] numbers;
public static void main(String[] args) throws Exception {
numbers = LongStream.rangeClosed(1, 10_000_000).toArray();
ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() + 1);
CompletionService
int taskSize = (int) (numbers.length / THRESHOLD);
for (int i = 1; i
final int key = i;
completionService.submit(new Callable
@Override
public Long call() throws Exception {
return sum((key - 1) * THRESHOLD, key * THRESHOLD);
}
});
}
long sumValue = 0;
for (int i = 0; i
sumValue += completionService.take().get();
}
// 所有任務已經完成,關閉執行緒池
System.out.println("sumValue = " + sumValue);
executor.shutdown();
}
private static long sum(int start, int end) {
long sum = 0;
for (int i = start; i
sum += numbers[i];
}
return sum;
}
}
使用 fork/join框架
分支/合併框架的目的是以遞迴的方式將可以並行的認為拆分成更小的任務,然後將每個子任務的結果合併起來生成整體結果;相關程式碼如下:
public class ForkJoinTest extends java.util.concurrent.RecursiveTask
private static final long serialVersionUID = 1L;
private final long[] numbers;
private final int start;
private final int end;
public static final long THRESHOLD = 10_000;
public ForkJoinTest(long[] numbers) {
this(numbers, 0, numbers.length);
}
private ForkJoinTest(long[] numbers, int start, int end) {
this.numbers = numbers;
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
int length = end - start;
if (length
return computeSequentially();
}
ForkJoinTest leftTask = new ForkJoinTest(numbers, start, start + length / 2);
leftTask.fork();
ForkJoinTest rightTask = new ForkJoinTest(numbers, start + length / 2, end);
Long rightResult = rightTask.compute();
// 注:join方法會阻塞,因此有必要在兩個子任務的計算都開始之後才執行join方法
Long leftResult = leftTask.join();
return leftResult + rightResult;
}
private long computeSequentially() {
long sum = 0;
for (int i = start; i
sum += numbers[i];
}
return sum;
}
public static void main(String[] args) {
System.out.println(forkJoinSum(10_000_000));
}
public static long forkJoinSum(long n) {
long[] numbers = LongStream.rangeClosed(1, n).toArray();
ForkJoinTask
return new ForkJoinPool().invoke(task);
}
}
上面的程式碼實現了 遞迴方式拆分子任務,並放入到執行緒池中執行。
作者:張雲飛Vir
連結:
來源:掘金
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4328/viewspace-2797497/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Java中的並行流處理與效能提升Java並行
- PyTorch中的多程序並行處理PyTorch並行
- Java多執行緒並行處理任務的實現Java執行緒並行
- 並行處理 Parallel Processing並行Parallel
- ArcGIS Desktop 工具的並行處理並行
- C#中的並行處理、並行查詢的方法你用對了嗎?C#並行
- JAVA基礎之七-Collection和它的並行和流處理Java並行
- nodejs“並行”處理嘗試NodeJS並行
- java當中的批處理Java
- java讀取大檔案並處理Java
- Go語言的 序列處理 和 並行處理 有什麼區別 ?Go並行
- Java中對時間的處理Java
- java中的垃圾處理機制Java
- 利用opencv進行簡易的拍照並處理照片OpenCV
- Java大型資料集合實現並行加速處理幾種方法 - DZoneJava並行
- MPP(大規模並行處理)簡介並行
- Java中的任務超時處理Java
- Java8中的時間處理Java
- Java 中的異常處理機制Java
- Netty中的執行緒處理EventLoopNetty執行緒OOP
- Java中的異常處理最佳實踐Java
- java優雅的處理程式中的異常Java
- mongoDB中聚合函式java處理MongoDB函式Java
- java中 檔案壓縮處理Java
- QT中跨執行緒警告的處理QT執行緒
- 50行爬蟲?️抓取並處理圖靈書目爬蟲圖靈
- MPP大規模並行處理架構詳解並行架構
- 《Java8實戰》-第七章筆記(並行資料處理與效能)Java筆記並行
- Java 異常處理中的種種細節!Java
- Java 中關於 null 物件的容錯處理JavaNull物件
- Java中的異常處理(隨堂筆記)Java筆記
- Java中處理SocketException: Connection reset”異常的方法JavaException
- Java 11:在Java中處理HTTP和WebSocket的新方法!JavaHTTPWeb
- Python資料預處理:Dask和Numba並行化加速!Python並行
- PyTorch 60 分鐘入門教程:資料並行處理PyTorch並行
- 04 Windows批處理中的條件執行Windows
- 【Java分享客棧】一文搞定CompletableFuture並行處理,成倍縮短查詢時間。Java並行
- Java處理emojiJava