併發編程模型和訪問控制

http://www.cnblogs.com/fxjwind/archive/2013/07/03/3170032.htmlhtml

 

http://www.eecs.harvard.edu/~mdw/papers/seda-sosp01.pdf, paperreact

Staged Event Driven Architecture (SEDA) 介紹web

 

併發的編程模型

1. 多線程模型

最爲傳統的模型, 爲每一個request起個新的thread去執行, 以實現併發 
最大的問題是, 擴展問題, request不少的時候, 太多的thread會產生很大的調度耗費, 固然可使用線程池來進行優化 
這種模型比較適合於CPU密集的request, 並設定近似於CPU核數的線程數, 達到併發計算的效果sql

還有就是併發粒度問題, 只能在request級別進行併發編程

image

 

2. 事件驅動模型

爲了解決併發粒度問題, 思路是把一個request拆成N個stage, 每一個stage都單獨一個FSM線程(有限狀態機), 並依賴中央scheduler進行統一協調 
當request到達的時候, 經過schdeuler依次發送event, 完成N個stage 
這樣解決擴展性問題, 由於是基於stage級別去併發, 因此就算有10000個request, 仍然只須要5個stage線程 
再者, 併發粒度比較小, 對於request中不一樣的stage能夠設置不一樣的併發度多線程

固然這個方案問題很明顯, 耦合度和複雜度比較高, 不一樣類型的request都須要實現一系列的FSM線程, 而且scheduler的實現會比較複雜併發

image

對比如今說的比較多的event-drive模型, 和這個仍是有差異的 
對於如今愈來愈多的web應用, 大部分應用都是I/O等待密集的request, 這種case使用多線程方式是很是低效的 
因此須要使用event-drive模型, Reactor模式, 用一個線程去等待10000個request和用10000個線程去等待, 效果上沒有區別, 可是耗費上卻天壤之別 
固然這種基於單線程的reactor模式, 只能節省I/O等待時間, 但對於CPU計算密集型的request由於是單線程, 因此就至關於串行執行 post

3. SEDA或Actor模型

沒看出SEDA和Actor兩種模型的差異, 思路和方法基本一致 
和event-based模型的關鍵不一樣, 就是去耦合和去中心化 
對於event-based, 須要scheduler知道全部的過程, 負責全部的event的發送和協調優化


但對於SEDA, 徹底的去耦合, 對於任一個stage, 都是獨立的, 徹底可重用的, stage之間徹底經過event進行溝通線程

對於每一個stage只須要知道, 下級stage是誰(將數據發送給誰), 開發人員能夠任意配置outgoing events, 從而造成workflow

對於stage級別的併發度, 經過設置thread pool就能夠簡單的設定

image

固然問題是, 依賴event queue, 效率上有些問題, LMAX Disruptor就是來解決這個效率瓶頸的

 

併發訪問控制

這個問題常常會和上面的問題混合在一塊, 這樣不清晰 
任一種併發的編程模型都會有訪問控制問題, 解決這個問題的方法其實也很簡單, 加鎖.

1. 悲觀鎖

徹底互斥鎖, 我作的時候, 你等着, 我作完, 你再作

簡單, 問題效率低

 

2. 樂觀鎖

妥協一點, 各自作各自的, 只在最終提交的時候, 去check當前的狀態是否已經變化, 若是已經變化那麼提交失敗 
根據最新的狀態, 處理邏輯後從新提交

 

3. MVCC (Multi-VersionConcurrencyControl)

另外一種思路, 不加鎖, 各寫各的, 因此咱們能夠同時保存相同數據的不一樣版本, 而後在client query的時候返回全部的版本, 讓client本身去決定選取什麼版本 
Nosql經常採用這種方式, 固然這個方法明顯加劇了client的負擔

 

4. STM (Software Transactional Memory)

STM實際上是綜合了MVCC和樂觀鎖機制, 比較典型的案例是, CouchDB和Clojure

用通俗的描述解釋一下, 
首先是MVCC, 你們均可以併發的隨意的在本身的版本上修改數據, 固然你的數據別人是看不得的 
而後是樂觀鎖, 當你想要commit的時候, 這個時候是須要加樂觀鎖的, commit的過程其實就是將公共的reference指向你的版本

爲何是transactional?  
由於你能夠在你的版本上作不少改動, 但僅僅當reference切換成功後, 全部的更新會被可見 
若是reference切換失敗, 全部的更新都不會被可見 
經過簡單的機制就是避免的rollback等複雜的操做, 可是卻達到了和transaction一樣的效果

因此就算你的更新沒有成功或因爲crash丟失了, 至少不會影響原來數據的一致性

相關文章
相關標籤/搜索