再談并發
上一篇python并發中講到了,使用多進程,多線程,多任務來加快程序的運行。其中講到的一點似乎有點問題,操作系統中線程是調度器的最小執行單位,那為何python中的多線程無法利用多核,只能在一個處理器上運行呢?因為python中有GIL(全局解釋器鎖)這么個東西,當然它只是cpython解釋器的一個特性,其他解釋器可能沒有。
大學時總在想,學操作系統、計算機組成原理、數據結構有啥用啊?還不如學習如何使用hibernate
、struts
、spring
。當你工作3年后,對如何使用這些工具再也提不起興趣時或者想深入了解它到底為什么是那樣時,你就會重新回過頭來打量大學時學的這些底層知識。
也許你對下面一句話耳熟能詳:
進程是資源分配的最小單位,線程是最小執行單位。
大學時讀的完全是字面意思啊?并沒有思考什么是進程,為何要搞出來個進程?好吧,下面又是我杜撰的。
進程是一個操作系統級別的概念,運行一個程序時往往需要各種資源,操作系統把一個程序以及運行時所需要的資源抽象成一個進程,這里的資源是存儲資源和計算資源。各個進程的計算資源是由操作系統的調度器統一分配的,而不是一個進程永遠霸占計算資源;因為進程使用的是虛擬內存地址,不同進程的同一虛擬地址可能映射到了不同的物理內存上,所以不同進程間的存儲資源是不共享的。
因為進程的儲存資源不共享,創建銷毀和切換的開銷比較大。所以出現了輕量級進程,即線程。線程是共享同一進程的存儲資源的,一個進程可以創建若干線程。同時它也是調度器的最小執行單元,可見多線程是能利用多核處理器的。
java沒有操作進程并發的類,官方暫時也不支持協程,但是有一些第三方庫,比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();}}
復制代碼