摘要:一并發和并行并發是同一時間應對多件事情的能力并行是同一時間做多件事情的能力。用并發的目的,不僅僅是為了讓程序并行運行從而發揮多核的優勢。函數式編程函數式編程日漸重要的原因之一,是其對并發編程和并行編程提供了良好的支持。
一、并發和并行:
并發是同一時間應對(dealing with)多件事情的能力;
并行是同一時間做(doing)多件事情的能力。
二、并行架構:
位級并行,32位計算機的運行速度比8位計算機更快,因為并行,對于32位數的加法,8位計算機必須進行多次8位計算,而32位計算機可以一步完成,即并行的處理32位的4字節。
指令級(instruction-level)并行,程序員通常可以不關心處理器內部并行的細節,因為盡管處理器內部的并行度很高,但是經過精心設計,從外部看上去所有處理都像是串行的。
數據級(data)并行,數據級并行(也稱為“單指令多數據”,SIMD)架構,可以并行地在大量數據上施加同一操作。這并不適合解決所有問題,但在適合的場景卻可以大展身手。
任務級(task-level)并行,終于來到了大家所認為的并行形式——多處理器。從程序員的角度來看,多處理器架構最明 顯的分類特征是其內存模型(共享內存模型或分布式內存模型)。
對于共享內存的多處理器系統,每個處理器都能訪問整個內存,處理器之間的通信主要通過內存進行。
對于分布式內存的多處理器系統,每個處理器都有自己的內存,處理器之間的通信主要通過網絡進行。
用并發的目的,不僅僅是為了讓程序并行運行從而發揮多核的優勢。若正確使用并發,程序還將獲得以下優點:及時響應、高效、容錯、簡單。
注意:不應該在產品代碼上,使用Thread類等底層服務。
三、七個模型
1、線程與鎖:線程與鎖模型有很多眾所周知的不足,但仍是其他模型的技術基礎,也是很多并 發軟件開發的首選。 2、函數式編程:函數式編程日漸重要的原因之一,是其對并發編程和并行編程提供了良好的支 持。函數式編程消除了可變狀態,所以從根本上是線程安全的,而且易于并行執行。 3、Clojure之道——分離標識與狀態:編程語言Clojure是一種指令式編程和函數式編程的混搭方 案,在兩種編程方式上取得了微妙的平衡來發揮兩者的優勢。 4、actor:actor模型是一種適用性很廣的并發編程模型,適用于共享內存模型和分布式內存模型, 也適合解決地理分布型問題,能提供強大的容錯性。 5、通信順序進程(Communicating Sequential Processes,CSP):表面上看,CSP模型與actor模 型很相似,兩者都基于消息傳遞。不過CSP模型側重于傳遞信息的通道,而actor模型側重于通道 兩端的實體,使用CSP模型的代碼會帶有明顯不同的風格。 6、數據級并行:每個筆記本電腦里都藏著一臺超級計算機——GPU。GPU利用了數據級并行, 不僅可以快速進行圖像處理,也可以用于更廣闊的領域。如果要進行有限元分析、流體力學計算 或其他的大量數字計算,GPU的性能將是不二選擇。 7、Lambda架構:大數據時代的到來離不開并行——現在我們只需要增加計算資源,就能具有 處理TB級數據的能力。Lambda架構綜合了MapReduce和流式處理的特點,是一種可以處理多種大數據問題的架構。
四、線程與鎖:
class Counter { private int count = 0; public synchronized void increment() { ++count; } public int getCount() { return count; } } 毋庸置疑,對于增加了同步功能的代碼,每次執行都將得到正確結果,但代碼中仍隱藏了一個bug。 潛藏的bug是: 除了increment()之外,getCount()方法 也需要進行同步。 否則,當一個線程對值的修改沒有及時更新到主內存,從而導致 調用getCount()的線程可能獲得一個失效的值。 解釋: Java內存模型定義了何時一個線程對內存的修改對另一個線程可見。 基本原則是,如果讀 線程和寫線程不進行同步,就不能保證可見性。 然而兩個線程都需要進行同步。只在其中一個線程進行同步是不夠的, 競態條件: 計算的正確性取決于多個線程的交替執行時序時,就會發生競態條件。 1、亂序執行。執行依賴于檢測的結果,而檢測結果依賴于多個線程的執行時序。 亂序原因: ? 編譯器的靜態優化可以打亂代碼的執行順序; ? JVM的動態優化也會打亂代碼的執行順序; ? 硬件可以通過亂序執行來優化其性能。
所以在多線程環境下,對一個文件的操作需要加鎖。
2、延遲初始化: 線程A和線程B同時執行getInstance,可能會取到兩個實例對象,主要看線程執行時序了。 public class ObjFactory { private Obj instance; public Obj getInstance(){ if(instance == null){ instance = new Obj(); } return instance; } }
五、來自外星方法的危害
規模較大的程序常用監聽器模式(listener)來解耦模塊。 在這里,我們構造一個類從一個URL 進行下載,并用ProgressListeners監聽下載的進度。 public class Downloader extends Thread { private InputStream in; private OutputStream out; private ArrayListlisteners; public Downloader(URL url,String outputFilename) throws IOException { in=url.openConnection().getInputStream(); out = new FileOutputStream(outputFilename); listeners=new ArrayList (); } public synchronized void addListener(ProgressListener listener){ listeners.add(listener); } public synchronized boolean remove(ProgressListener listener){ return listeners.remove(listener); } /*** * 來自外星方法的危害 * * addListener()、removeListener()和updateProgress()都是同步方法, * 多線程可以安全地使用這些方法。盡管這段代碼僅使用了一把鎖,但仍隱藏著一個死鎖陷阱。 * * 陷阱在于updateProgress()調用了一個外星方法——但對于這個外星方法一無所知。外星方法可以做任何事情, * 例如持有另外一把鎖。這樣一來,我們就在對加鎖順序一無所知的情況下使用了兩把鎖。就像前面提到的,這就有可能發生死鎖。 * * @param n */ private synchronized void updateProgress(int n){ for(ProgressListener listener:listeners){ listener.onProgress(n); } } /*** * 一種方法是在遍歷之前對listeners進行保 護性復制(defensive copy), * 再針對這份副本進行遍歷 * 這是個一石多鳥的方法。不僅在調用外星方法時不用加鎖,而且大大減少了代碼持有鎖的時間。 * 長時間地持有鎖將影響性能(降低了程序的并發度),也會增加死鎖的可能。 * @param n */ private void updateProgress2(int n){ ArrayList listenersCopy=null; synchronized (this){ listenersCopy=(ArrayList )listeners.clone(); } for(ProgressListener listener:listenersCopy){ listener.onProgress(n); } } @Override public void run(){ int n = 0, total = 0; byte[] buffer = new byte[1024]; try { while((n = in.read(buffer)) != -1) { out.write(buffer, 0, n); total += n; updateProgress(total); } out.flush(); } catch (IOException e) { e.printStackTrace(); } } }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/68656.html
摘要:使用進行并發編程篇三掘金這是使用進行并發編程系列的最后一篇。所以我考慮啟用一個本地使用進行并發編程篇二掘金我們今天繼續深入學習。 使用 Python 進行并發編程 - asyncio 篇 (三) - 掘金 這是「使用Python進行并發編程」系列的最后一篇。我特意地把它安排在了16年最后一天。 重新實驗上篇的效率對比的實現 在第一篇我們曾經對比并發執行的效率,但是請求的是httpb...
摘要:并發表示在一段時間內有多個動作存在。并發帶來的問題在享受并發編程帶來的高性能高吞吐量的同時,也會因為并發編程帶來一些意想不到弊端。并發過程中多線程之間的切換調度,上下文的保存恢復等都會帶來額外的線程切換開銷。 0x01 什么是并發 要理解并發首選我們來區分下并發和并行的概念。 并發:表示在一段時間內有多個動作存在。 并行:表示在同一時間點有多個動作同時存在。 例如:此刻我正在寫博客,但...
摘要:因為多線程競爭鎖時會引起上下文切換。減少線程的使用。舉個例子如果說服務器的帶寬只有,某個資源的下載速度是,系統啟動個線程下載該資源并不會導致下載速度編程,所以在并發編程時,需要考慮這些資源的限制。 最近私下做一項目,一bug幾日未解決,總惶恐。一日頓悟,bug不可怕,怕的是項目不存在bug,與其懼怕,何不與其剛正面。 系列文章傳送門: Java多線程學習(一)Java多線程入門 Jav...
摘要:關于并發編程,其目的就是為了讓程序運行得更快,但是,并不是啟動更多的線程就能讓程序更大限度的并發執行。對于軟件資源限制考慮使用資源池將資源復用,例如數據庫連接池等資源限制情況下進行并發編程根據不同的資源限制調整程序的并發度。 關于并發編程,其目的就是為了讓程序運行得更快,但是,并不是啟動更多的線程就能讓程序更大限度的并發執行。有哪些影響并發編程的因素呢? 一、文章導圖 showImg(...
摘要:相比與其他操作系統包括其他類系統有很多的優點,其中有一項就是,其上下文切換和模式切換的時間消耗非常少。因為多線程競爭鎖時會引起上下文切換。減少線程的使用。很多編程語言中都有協程。所以如何避免死鎖的產生,在我們使用并發編程時至關重要。 系列文章傳送門: Java多線程學習(一)Java多線程入門 Java多線程學習(二)synchronized關鍵字(1) java多線程學習(二)syn...
閱讀 1305·2021-10-08 10:05
閱讀 4127·2021-09-22 15:54
閱讀 3113·2021-08-27 16:18
閱讀 3112·2019-08-30 15:55
閱讀 1445·2019-08-29 12:54
閱讀 2754·2019-08-26 11:42
閱讀 550·2019-08-26 11:39
閱讀 2135·2019-08-26 10:11