標籤:
多核的處理器不同於單核處理器,可以同時執行多個線程。可以說,在理論上雙核的處理器的效能是單核的兩倍,基本上我們一般不用操心這個裝置到底是多核還是單核的,因為使用Thread或者AsyTask將工作指派給不同線程就足夠了。如果處理器是多核的,那這些線程就會運行在不同的核心上,但是可能有的時候要最有效使用CPU來獲得可接受的效能,要特別為多核定製演算法。
以下實現做的事情:
1.將原問題劃分成多個更簡單的子問題
2.然後將子問題的結果合并處理,算出原問題的解(使用Future和ExcecutorService)
3.成功避免了重複計算很多相同的斐波那契數(使用高並發高吞吐並且安全執行緒的ConcurrentHashMap作為緩衝)
代碼如下:
private static final int proc = Runtime.getRuntime().availableProcessors(); private static final ExecutorService executorService = Executors.newFixedThreadPool(proc + 2); public static BigInteger recursiveFasterBigInteger(int n ){ if(n>1) { int m = (n/2) + (n&1); BigInteger fM = recursiveFasterBigInteger(m); BigInteger fM_1 = recursiveFasterBigInteger(m-1); //合并結果,計算出原問題的解 if((n&1)==1){ return fM.pow(2).add(fM_1.pow(2)); }else { return fM_1.shiftLeft(1).add(fM).multiply(fM); } } return (n==0)?BigInteger.ZERO:BigInteger.ONE; } private static BigInteger recursiveFasterWithCache(int n) { HashMap<Integer, BigInteger> cache = new HashMap<Integer, BigInteger>(); return recursiveFasterWithCache(n, cache); } private static BigInteger recursiveFasterWithCache(int n, Map<Integer, BigInteger> cache) { if (n > 92) { BigInteger fN = cache.get(n); if (fN == null) { int m = (n / 2) + (n & 1); BigInteger fM = recursiveFasterWithCache(m, cache); BigInteger fM_1 = recursiveFasterWithCache(m - 1, cache); if ((n & 1) == 1) { fN = fM.pow(2).add(fM_1.pow(2)); } else { fN = fM_1.shiftLeft(1).add(fM).multiply(fM); } cache.put(n, fN); } return fN; } return BigInteger.valueOf(iterativeFaster(n)); } public static BigInteger recursiveFasterWithCacheAndThread(int n) { int proc = Runtime.getRuntime().availableProcessors(); if (n < 128 || proc <= 1) { return recursiveFasterWithCache(n); } final ConcurrentHashMap<Integer, BigInteger> cache = new ConcurrentHashMap<Integer, BigInteger>(); final int m = (n / 2) + (n & 1); Callable<BigInteger> callable = new Callable<BigInteger>() { @Override public BigInteger call() throws Exception { return recursiveFasterWithCache(m,cache); } }; Future<BigInteger> ffM = executorService.submit(callable); callable = new Callable<BigInteger>() { @Override public BigInteger call() throws Exception { return recursiveFasterWithCache(m-1,cache); } }; Future<BigInteger> ffM_1 = executorService.submit(callable); //得到各部分的結果開始合并 BigInteger fM,fM_1,fN; try{ fM = ffM.get();//擷取第一個子問題的結果(阻塞調用) }catch (Exception e){ //如果拋出了異常 那就在當前主線程中計算fM fM = recursiveFasterBigInteger(m); } try{ fM_1 = ffM_1.get();//擷取第一個子問題的結果(阻塞調用) }catch (Exception e){ //如果拋出了異常 那就在當前主線程中計算fM fM = recursiveFasterBigInteger(m-1); } if((n & 1) != 0 ){ fN = fM.pow(2).add(fM_1.pow(2)); }else { fN = fM_1.shiftLeft(1).add(fM).multiply(fM); } return fN; }
其實很多時候即使把問題分解為子問題並將子問題指派到不同的線程,效能也有可能並沒有什麼提升,有可能是資料之間有依賴,不得不進行同步,線程就可能會花大部分的時間在等待資料。所以實踐中通常是用多線程執行無關的任務,避免同步需求。
Android 應用效能最佳化(三) 多核下的多線程計算