再談并發(fā)
上一篇python并發(fā)中講到了寂嘉,使用多進程奏瞬,多線程,多任務來加快程序的運行泉孩。其中講到的一點似乎有點問題硼端,操作系統(tǒng)中線程是調(diào)度器的最小執(zhí)行單位,那為何python中的多線程無法利用多核寓搬,只能在一個處理器上運行呢珍昨?因為python中有GIL(全局解釋器鎖)這么個東西,當然它只是cpython解釋器的一個特性句喷,其他解釋器可能沒有镣典。
大學時總在想,學操作系統(tǒng)唾琼、計算機組成原理兄春、數(shù)據(jù)結(jié)構(gòu)有啥用啊锡溯?還不如學習如何使用hibernate
赶舆、struts
、spring
祭饭。當你工作3年后芜茵,對如何使用這些工具再也提不起興趣時或者想深入了解它到底為什么是那樣時,你就會重新回過頭來打量大學時學的這些底層知識倡蝙。
也許你對下面一句話耳熟能詳:
進程是資源分配的最小單位夕晓,線程是最小執(zhí)行單位。
大學時讀的完全是字面意思坝圃邸?并沒有思考什么是進程征炼,為何要搞出來個進程析既?好吧,下面又是我杜撰的谆奥。
進程是一個操作系統(tǒng)級別的概念眼坏,運行一個程序時往往需要各種資源,操作系統(tǒng)把一個程序以及運行時所需要的資源抽象成一個進程酸些,這里的資源是存儲資源和計算資源宰译。各個進程的計算資源是由操作系統(tǒng)的調(diào)度器統(tǒng)一分配的,而不是一個進程永遠霸占計算資源魄懂;因為進程使用的是虛擬內(nèi)存地址沿侈,不同進程的同一虛擬地址可能映射到了不同的物理內(nèi)存上,所以不同進程間的存儲資源是不共享的市栗。
因為進程的儲存資源不共享缀拭,創(chuàng)建銷毀和切換的開銷比較大咳短。所以出現(xiàn)了輕量級進程,即線程蛛淋。線程是共享同一進程的存儲資源的咙好,一個進程可以創(chuàng)建若干線程。同時它也是調(diào)度器的最小執(zhí)行單元打肝,可見多線程是能利用多核處理器的淋样。
java沒有操作進程并發(fā)的類各吨,官方暫時也不支持協(xié)程,但是有一些第三方庫层宫,比Quasar。下面是多線程的幾種方式:
- 通過
ThreadPoolExecutor
- 通過
CompletableFuture
- 通過流的并行處理
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.*;
import java.util.stream.IntStream;
public class ThreadPoolDemo {
static String content = "1234567890abcdefghijklmnopqrstuvwxyz";
static int size = 400;
public static void a(){
int cnt = Runtime.getRuntime().availableProcessors() * 2 + 1;
ExecutorService threadPoolExecutor = Executors.newFixedThreadPool(cnt);
ArrayList<Future<?>> fs = new ArrayList<>(size);
long start = System.currentTimeMillis();
for(int i = 0; i < size; ++i){
int seq = i;
Future<?> f = threadPoolExecutor.submit(() -> createFile("a", seq));
fs.add(f);
}
for(Future<?> f : fs){
try {
f.get();
} catch (InterruptedException|ExecutionException e) {
e.printStackTrace();
}
}
System.out.println(String.format("%s = %s", "a", (System.currentTimeMillis() - start)));
threadPoolExecutor.shutdown();
}
public static void b(){
CountDownLatch countDownLatch = new CountDownLatch(size);
long start = System.currentTimeMillis();
for(int i = 0;i<size;++i){
int seq = i;
CompletableFuture
.runAsync(()->createFile("b", seq))
.whenComplete((r, e)->{
countDownLatch.countDown();
});
}
try {
countDownLatch.await();
System.out.println(String.format("%s = %s", "b", (System.currentTimeMillis() - start)));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void c(){
long start = System.currentTimeMillis();
IntStream.range(0, size)
.parallel()
.forEach(e -> {
createFile("c", e);
});
System.out.println(String.format("%s = %s", "c", (System.currentTimeMillis() - start)));
}
public static void createFile(String prefix, int name){
File file = new File("D:/files/" + prefix + "_" + name);
if(!file.exists()){
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
try (FileOutputStream fos = new FileOutputStream(file)) {
fos.write(content.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
// a();
//b();
c();
}
}