浅谈0/1切换
?
前言:
做過GUI開發的同學, 都知曉雙緩存機制. 其過程為先把所有的場景和實體對象畫到一個備份canvas, 然后再把備份canvas的內容整個填充真正的畫板canvas中. 如果不采用雙緩存機制, 你的畫面有可能會出現閃爍和抖動.
究其原因是整個繪制過程, 包含清屏, 繪制場景和各個實體. 其耗時遠遠大于單個canvas的復制. 進而導致CPU寫canvas的速率小于LCD讀取canvas的速率. 這樣就出現閃爍的現象了.
在后臺服務中, 也會遇到類似的情形: 當數據/資源需要更新時, 采用直接增量更新的方式代價大(耗時長, 阻塞服務可用/實時響應), 由此引入back buffer,做0/1切換.
本文以"配置文件熱載更新"為例, 著重介紹0/1切換的思路和優化技巧.
熱載更新:
以往更新配置時, 往往需要重啟服務進程. 為了提高服務的可用性, 更方便運維.
采取的改進方式是:
1) 引入配置中心服務(ConfigServer)
把模塊的配置文件擱置在ConfigServer中, 具體模塊從ConfigServer中獲取(拉起/通知).
2) 監控本地配置文件變更
進程模塊通過定期輪詢/事件觸發的方式, 感知配置文件是否發生變化, 若發生變化, 則重新載入.
但無論采用何種方式, 勢必存在切換過程.
切換特點:
把切換的雙方定義為前端和后端, 前端資源往往被N個線程訪問(靜態只讀), 后端資源往往是一個線程更新寫. 于是就形成了一個N讀1寫的格局.
具體在c/c++實現時, 切換過程往往就是一個指針的重新賦值, 十分簡單.
但問題也就隱藏在這了, 在切換后的舊資源銷毀過程中, 存在多線程的競態沖突風險.
有人可能會提議, 如果對資源的訪問和資源的切換加相同的鎖保護, 就沒有這個問題. 但在低頻率切換的場景下, 加鎖帶來的性能損失, 有些得不償失.
無鎖0/1切換:
是否存在無鎖的切換方式呢?
1). 延遲銷毀
工作線程持有并訪問舊資源句柄時間不長, 可以設定一個時間窗口, 該時間窗口內屬于保護期, 禁止對舊資源進行銷毀.
注: 在絕大多數場景下, 該方案滿足條件. 只是理論上, 不排除低概率事件.
2). 帶引用計數的智能指針切換
我們借助boost的shared_ptr來構建切換的小例子
巧用boost::shared_ptr內部有個原子計數器和代理指針, 借助RAII的思想完美的實現了無引用時的自動清理工作. 也避免了上述的競態沖突.
總結:
在服務模塊中的0/1切換有很多, 這邊簡述了下解決方案, 沒有細致展開, 權當個人的學習筆記.
寫在最后:
如果你覺得這篇文章對你有幫助, 請小小打賞下. 其實我想試試, 看看寫博客能否給自己帶來一點小小的收益. 無論多少, 都是對樓主一種由衷的肯定.
?
?
轉載于:https://www.cnblogs.com/mumuxinfei/p/4466000.html
總結
- 上一篇: discuz中又拍云在ie8,chrom
- 下一篇: 全国计算机等级考试题库二级C操作题100