среда, 20 декабря 2017 г.

Golang sync.Map

      sync.Map в появившийся в Golang 1.9 оказался довольно занятной штуковиной. Я посмотрел видео с конференции:
 Перечитал еще раз слайды - https://github.com/gophercon/2017-talks/blob/master/lightningtalks/BryanCMills-AnOverviewOfSyncMap/An%20Overview%20of%20sync.Map.pdf но все равно не мог четко понять - в каких случаях стоит использовать sync.Map а в каких обычный map[] + mutex. Может недостаточно понятно написано, может просто я такой одаренный. В общем мне чтобы разобраться нужно залезть в исходники, что я собственно и сделал - https://golang.org/src/sync/map.go?s=822:2269#L16
          Итак под капотом sync.Map находятся две map[] - readonly map и dirty map. Readonly map используется для быстрого чтения/записи уже существующих значений. В readonly map храниться не само значение а указатель на него. Для чтений значения используется  atomic.LoadPointer(), для записи - atomic.CompareAndSwapPointer(). Это так называемый fastpath, то есть собственно для чего все и затевалось. И используем мы этот fastpath если пишем или читаем значения по уже существующим ключам. Все остальное - происходит уже не так быстро. В случае если мы вставляем новое значение - оно попадает в dirty map. Все операции с dity map происходят с заблокированным мютексом. После какого-то количества cache miss - попыток чтения новых значений из readonly map происходит промоушен dirty map до readonly map.  После этого все недавно добавленные ключи можно будет читать писать без блокировки. 
        Итого: читаем/пишем по существующим ключам очень быстро (сильно быстрее map + mutex),  потребляем в 2 раза больше памяти на указатели/хэш таблицы(dirty map также хранит все ключи из readonly map). Но размер значений тут никакой роли не играет, так как мы не храним значения а только указатели на них.  Добавление новых ключей и look up по вновь добавленным ключам происходит сильно медленнее обычной map + mutex потому что появляется дополнительный indirection level(указатели), и сами операции с ними - atomic, а это значит много memory barrier-ов.