ARTS 是陳浩(網名左耳朵耗子)在極客時間專欄裏發起的一個活動,目的是經過分享的方式來堅持學習。golang
每人每週寫一個 ARTS:Algorithm 是一道算法題,Review 是讀一篇英文文章,Technique/Tips 是分享一個小技術,Share 是分享一個觀點。
本週的 ARTS 你將看到:算法
本週的算法題是 LeetCode 第 42 題「接雨水」—— Trapping Rain Water。編程
我知道這道題各類五花八門的解法,可是若是解法自己太有技巧性的話,反而失去了練習算法題的目的。因此只列舉兩種我認爲最「直觀」的解法。數組
// brute force func trap_bf(height []int) int { ans := 0 for i := 0; i < len(height); i++ { lm, rm := 0, 0 for l := i; l >= 0; l-- { lm = max(lm, height[l]) } for r := i; r < len(height); r++ { rm = max(rm, height[r]) } ans += min(lm, rm) - height[i] } return ans } // 相似 DP 的思想 func trap_dp(height []int) int { n := len(height) if n == 0 { return 0 } ans := 0 lm, rm := make([]int, n), make([]int, n) lm[0] = height[0] for i := 1; i < n; i++ { lm[i] = max(lm[i-1], height[i]) } rm[n-1] = height[n-1] for i := n-2; i >= 0; i-- { rm[i] = max(rm[i+1], height[i]) } for i := 0; i < n; i++ { ans += min(rm[i], lm[i]) - height[i] } return ans }
本週沒有特別值得推薦的文章。安全
接下來咱們聊聊關於 Go 語言sync.Map
也就是併發安全字典類型的底層實現。併發
sync.Map
這個類型在平時開發中用的並非很是多,並且在比較早期的版本中 Go 也並無官方提供一個併發安全的 map. 官方這個作法的緣由從普通 map 在檢測到併發讀寫時的報錯fatal error: concurrent map writes
可見一斑。至於爲何不容許直接併發地使用 map,官方 blog 是這樣解釋的:app
After long discussion it was decided that the typical use of maps did not require safe access from multiple goroutines, and in those cases where it did, the map was probably part of some larger data structure or computation that was already synchronized. Therefore requiring that all map operations grab a mutex would slow down most programs and add safety to few. This was not an easy decision, however, since it means uncontrolled map access can crash the program.
後來可能由於呼聲過高,官方仍是提供了一個基於 map 類型的擴展,即sync.Map
. 這個擴展的基本思路就是維護兩個 map 類型對象:read
和dirty
,讀去 map 中的 kv 時儘量只從 read 中去讀,向 map 中寫入 kv 的時候會寫到 dirty 中。固然爲了保持 read 和 dirty 的一致會作一些額外的標記工做。好比,當 dirty 中包含太多 read 中沒有的新 kv 的時候就會將 dirty 中的內容直接升級爲 read(即將 dirty 的值直接賦給 read 並置 dirty 爲 nil)。這樣作的最終目的就是分離讀寫,在併發讀取sync.Map
中的值的時候無需加鎖,在讀寫併發或者寫寫併發的時候纔會使用鎖,從而下降使用鎖對性能的影響。ide
固然,目前實現方式的代價就是sync.Map
適合讀多寫少的狀況場景,若是寫入佔比過大的話就會致使sync.Map
性能降低。另外在使用過程當中還要儘可能關注類型安全。post
關於具體的源碼解析能夠看看下面的這兩篇文章,算是比較詳細的中文sync.Map
源碼解讀了。性能
最後,仍是建議打開這部分的源碼,對照其餘文章來看,效率最高。
最近在學習一些技術實現細節的時候,在感受到不一樣的技術確實是「相通」的同時,對於一個開發者真正的「開發能力」是什麼這個問題很是迷惑。我想致使這種迷惑的緣由極可能是我所謂的「學習」能夠提高知識量,但不能真正提高我寫代碼的能力。這種「寫代碼的能力」最終仍是要經過不停的項目實踐才能得到的,單純的學習只能得到寫好代碼的前期技能儲備,但實踐纔是沒法逃避的能力提高途徑。
sync.RWMutex
處理 cache contention 的時間複雜度是 O(N).