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