併發與並行區別
併發:當有多個線程在操作時,如果系統只有一個CPU(單核心),則它根本不可能真正同時進行一個以上的線程,它只能把CPU運行時間劃分成若干個時間段,再將時間 段分配給各個線程執行,在一個時間段的線程代碼運行時,其它線程處於掛起狀。.這種方式我們稱之爲併發(Concurrent)。
並行:當系統有一個以上CPU(一個CPU具備多核心)時,則線程的操作有可能非併發。當一個CPU執行一個線程時,另一個CPU可以執行另一個線程,兩個線程互不搶佔CPU資源,可以同時進行,這種方式我們稱之爲並行(Parallel)。
區別:併發和並行是即相似又有區別的兩個概念,並行是指兩個或者多個事件在同一時刻發生;而併發是指兩個或多個事件在同一時間間隔內發生。在多道程序環境下,併發性是指在一段時間內宏觀上有多個程序在同時運行,但在單處理機系統中,每一時刻卻僅能有一道程序執行,故微觀上這些程序只能是分時地交替執行。倘若在計算機系統中有多個處理機,則這些可以併發執行的程序便可被分配到多個處理機上,實現並行執行,即利用每個處理機來處理一個可併發執行的程序,這樣,多個程序便可以同時執行。
實際的數據統計範例
某公司有4個工廠,分佈在不同地區,同一時段都生產了P1,P2,P3這3種產品,產量(單位;噸),
工廠\產品 | P1 | P2 | P3 |
---|---|---|---|
甲 | 5 | 2 | 4 |
乙 | 3 | 8 | 2 |
丙 | 6 | 0 | 4 |
丁 | 0 | 1 | 6 |
可用下面的矩陣描述
,其中4行分別表示甲乙丙丁4個工廠的生產情況,3列分佈表示3種產品P1,P2,P3的產量。
產品P1的單件利潤爲2(單位:元)佔用存儲空間爲4(單位:立方米),
產品P2的單件利潤爲1(單位:元)佔用存儲空間爲3單位:立方米),
產品P3的單件利潤爲3(單位:元)佔用存儲空間爲4單位:立方米),
試用矩陣的計算方式來統計這些數據。
產品 | 單件利潤/單件體積 |
P1 | 2/4 |
P2 | 1/3 |
P3 | 3/2 |
可用下面的矩陣描述
,其中第1列表示3種產品的單件利潤,第2列表示3種產品的單件體積。
矩陣C的第1列數據分別表示4個工廠的利潤,第2列分別表示4個工廠產品需要的存儲空間。
我們將使用Java代碼來實現數據的統計
定義存儲矩陣數據的對象:
package com.contoso;
public class Matrix {
private final int[][] matrix;
public Matrix(int rows, int cols) {
matrix = new int[rows][cols];
}
public int getCols() {
return matrix[0].length;
}
public int getRows() {
return matrix.length;
}
public int getCellValue(int row, int col) {
return matrix[row][col];
}
public void setCellValue(int row, int col, int value) {
matrix[row][col] = value;
}
}
接下來我們將使用兩種不同的實現方式來統計數據:
第1種方式:單線程統計方式
package com.contoso;
/**
* 單線程矩陣乘法
*
*/
public class MatrixMultiply {
public static void main(String[] args) {
/*
A矩陣:4行3列
5 2 4
3 8 2
6 0 4
0 1 6
*/
long start = System.nanoTime();
Matrix a = new Matrix(4, 3);
a.setCellValue(0, 0, 5);
a.setCellValue(0, 1, 2);
a.setCellValue(0, 2, 4);
a.setCellValue(1, 0, 3);
a.setCellValue(1, 1, 8);
a.setCellValue(1, 2, 2);
a.setCellValue(2, 0, 6);
a.setCellValue(2, 1, 0);
a.setCellValue(2, 2, 4);
a.setCellValue(3, 0, 0);
a.setCellValue(3, 1, 1);
a.setCellValue(3, 2, 6);
print(a);
/*
B矩陣:3行2列
2 4
1 3
3 2
*/
Matrix b = new Matrix(3, 2);
b.setCellValue(0, 0, 2);
b.setCellValue(1, 0, 1);
b.setCellValue(2, 0, 3);
b.setCellValue(0, 1, 4);
b.setCellValue(1, 1, 3);
b.setCellValue(2, 1, 2);
print(b);
/*
C矩陣:4行2列 C = A * B
*/
print(multiply(a, b));
long end = System.nanoTime();
double timeTaken = (end - start) / 1e9;
System.out.println("Matrix Multiply Time Taken in seconds:" + timeTaken);
}
public static void print(Matrix mat) {
for (int i = 0; i < mat.getRows(); i++) {
for (int j = 0; j < mat.getCols(); j++) {
System.out.printf("%d ", mat.getCellValue(i, j));
}
System.out.println();
}
System.out.println();
}
public static Matrix multiply(Matrix a, Matrix b) {
if (a.getCols() != b.getRows()) {
throw new IllegalArgumentException("rows/columns mismatch");
}
Matrix result = new Matrix(a.getRows(), b.getCols());
for (int i = 0; i < a.getRows(); i++) {
for (int j = 0; j < b.getCols(); j++) {
for (int k = 0; k < a.getCols(); k++) {
result.setCellValue(i, j, result.getCellValue(i, j) + a.getCellValue(i, k) * b.getCellValue(k, j));
}
}
}
return result;
}
}
請注意以下單線程統計需要的時間:
run:
5 2 4
3 8 2
6 0 4
0 1 6
2 4
1 3
3 2
24 34
20 40
24 32
19 15
Matrix Multiply Time Taken in seconds:0.036336188
BUILD SUCCESSFUL (total time: 0 seconds)
第2中方式:超快並行執行的多核心CPU矩陣乘法在數據統計方面的應用
package com.contoso;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
/**
* 超快並行執行的多核心CPU矩陣乘法在數據統計方面的應用
*
*/
public class RecursiveMatrixMultiply extends RecursiveAction {
private final Matrix a, b, c;
private final int row;
public RecursiveMatrixMultiply(Matrix a, Matrix b, Matrix c) {
this(a, b, c, -1);
}
public RecursiveMatrixMultiply(Matrix a, Matrix b, Matrix c, int row) {
if (a.getCols() != b.getRows()) {
throw new IllegalArgumentException("rows/columns mismatch");
}
this.a = a;
this.b = b;
this.c = c;
this.row = row;
}
@Override
public void compute() {
if (row == -1) {
List<RecursiveMatrixMultiply> tasks = new ArrayList<>();
for (int row = 0; row < a.getRows(); row++) {
tasks.add(new RecursiveMatrixMultiply(a, b, c, row));
}
invokeAll(tasks);
} else {
multiplyRowByColumn(a, b, c, row);
}
}
public static void multiplyRowByColumn(Matrix a, Matrix b, Matrix c, int row) {
for (int j = 0; j < b.getCols(); j++) {
for (int k = 0; k < a.getCols(); k++) {
c.setCellValue(row, j, c.getCellValue(row, j) + a.getCellValue(row, k) * b.getCellValue(k, j));
}
}
}
public static void print(Matrix mat) {
for (int i = 0; i < mat.getRows(); i++) {
for (int j = 0; j < mat.getCols(); j++) {
System.out.print(mat.getCellValue(i, j) + " ");
}
System.out.println();
}
System.out.println();
}
public static void main(String[] args) {
long start = System.nanoTime();
/*
A矩陣:4行3列
5 2 4
3 8 2
6 0 4
0 1 6
*/
Matrix a = new Matrix(4, 3);
a.setCellValue(0, 0, 5);
a.setCellValue(0, 1, 2);
a.setCellValue(0, 2, 4);
a.setCellValue(1, 0, 3);
a.setCellValue(1, 1, 8);
a.setCellValue(1, 2, 2);
a.setCellValue(2, 0, 6);
a.setCellValue(2, 1, 0);
a.setCellValue(2, 2, 4);
a.setCellValue(3, 0, 0);
a.setCellValue(3, 1, 1);
a.setCellValue(3, 2, 6);
print(a);
/*
B矩陣:3行2列
2 4
1 3
3 2
*/
Matrix b = new Matrix(3, 2);
b.setCellValue(0, 0, 2);
b.setCellValue(1, 0, 1);
b.setCellValue(2, 0, 3);
b.setCellValue(0, 1, 4);
b.setCellValue(1, 1, 3);
b.setCellValue(2, 1, 2);
print(b);
/*
C矩陣:4行2列 C = A * B
*/
Matrix c = new Matrix(4, 2);
ForkJoinPool pool = new ForkJoinPool();
pool.invoke(new RecursiveMatrixMultiply(a, b, c));
print(c);
long end = System.nanoTime();
double timeTaken = (end - start) / 1e9;
System.out.println("Recursive Matrix Multiply Time Taken in seconds:" + timeTaken);
System.err.println("單顆CPU內核數 = " + Runtime.getRuntime().availableProcessors());
}
}
請注意並行計算的多核心CPU矩陣乘法統計需要的時間:
run:
5 2 4
3 8 2
6 0 4
0 1 6
2 4
1 3
3 2
24 34
20 40
24 32
19 15
單顆CPU內核數 = 4
Recursive Matrix Multiply Time Taken in seconds:0.003261084
BUILD SUCCESSFUL (total time: 0 seconds)