性能與可伸縮性(第十一章)

性能與可伸縮性

性能包括:服務時間、延遲時間、吞吐率、效率、容量等 可伸縮性:當增長計算資源時(例如CPU、內存、存儲容量或I/O帶寬),程序的吞吐量或者處理能力能相應地增長 當進行性能調優時,其目的一般是用更小的代價完成相同的工做,例如經過緩存來重用以前計算的結果。 當進行可伸縮性調優時,其目的是設法將問題的計算並行化,從而能利用更多的計算資源來完成更多的工做。數組

在全部併發程序中都包含一些串行部分,若是你認爲在你的程序中不存在串行部分,那麼能夠再仔細檢查一遍。緩存

1. 線程引入的開銷

  • 上下文切換
  • 內存同步
  • 阻塞

2. 減小鎖的競爭

在併發程序中,對可伸縮性的最主要威脅就是獨佔方式的資源鎖。有兩個因素將影響在鎖上發生競爭的可能性:鎖的請求頻率、每次持有該鎖的時間。若是兩者的乘積很小,那麼大多數獲取鎖的操做都不會發生競爭,所以在該鎖上的競爭不會對伸縮性形成嚴重影響。併發

有3種方式能夠下降鎖的競爭程度:
    1. 減小鎖的持有時間
    2. 下降鎖的請求頻率
    3. 使用帶有協調機制的獨佔鎖,這些機制容許更高的併發性
  • 縮小鎖的範圍(「快進快出」)

下降發生競爭可能性的一種有效方式就是儘量縮短鎖的持有時間。例如能夠將一些與鎖無關的代碼移出同步代碼塊,尤爲是那些開銷較大的操做,以及可能被阻塞的操做,例如I/O性能

  • 減少鎖的粒度

下降線程請求鎖的頻率(從而減少發生競爭的可能性)。這能夠經過鎖分解和鎖分段等技術來實現。在這些技術中將採用多個相互獨立的鎖來保護獨立的狀態變量,從而改變這些變量在以前由單個鎖來保護的狀況。 這些技術能減少鎖操做的粒度,並能實現更高的可伸縮性,然而,使用的鎖越多,那麼發生死鎖的風險也就越高。優化

若是一個鎖須要保護多個相互獨立的狀態變量,那麼能夠將這個鎖分解爲多個鎖,而且每一個鎖只保護一個變量,從而提升可伸縮性,並最終下降每一個鎖被請求的頻率。
  • 鎖分段

將鎖分解技術進一步擴展爲對一組獨立對象上的鎖進行分解,這種狀況被稱爲「鎖分段」。例如,在ConcurrentHashMap的實現中使用了一個包含16個鎖的數組,每一個鎖保護全部散列桶的1/16,其中第N個散列桶由第(N mod 16)個鎖來保護。線程

鎖分段的一個劣勢在於:與採用單個鎖來實現獨佔訪問相比,要獲取多個鎖來實現獨佔訪問將更加困難而且開銷更高(在進行某些操做後,須要獲取全部的鎖)。
  • 避免熱點域

當每一個操做都請求多個變量時,鎖的粒度將很難下降。這是在性能與可伸縮性之間相互制衡的另外一個方面。一些常見的優化措施,例如將一些反覆計算的結果緩存起來,都會引入一些「熱點域(Hot Field)」,而這些熱點域每每會限制可伸縮性。code

  • 一些代替獨佔鎖的方法

另外一種下降鎖競爭的技術就是放棄使用獨佔鎖,從而有助於使用一種友好併發的方式來管理共享狀態。例如,使用併發容器、讀-寫鎖、不可變對象以及原子變量。對象

  • 向對象池說「不」

3. 減小上下文切換的開銷

在許多任務中都包含一些可能被阻塞的操做。當任務在運行和阻塞這兩個狀態之間切換時,就至關於一次上下文切換。要提升性能,就要減小這樣的切換。內存

相關文章
相關標籤/搜索