Горутинова спокуса. Приклади використання горутин, де вони насправді зайві
Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті
Це компактна збірка прикладів використання горутин, де вони насправді зайві.
Передісторія або просто додайте «go»
На Golang просто розробляти і також розпаралелити збереження статистики, збереження онлайну або схожі задачі, додавши ключове слово go.
Така простота допомагає зосередитись на бізнес-логіці але інколи призводить до бездумного додання go перед задачами які можна розпаралелити.
Приклад перший, запуск горутини в кінці горутини
package main import ( "fmt" "log" "net/http" "time" ) func endLongtimeAction(now int64) { time.Sleep(time.Microsecond) // some logic log.Printf("endLongtimeAction %d", now) } func longtimeAction(now int64) { time.Sleep(time.Microsecond) // some logic log.Printf("longtimeAction %d", now) // useless start goroutine go endLongtimeAction(now) } func hello(w http.ResponseWriter, r *http.Request) { // useful start goroutine go longtimeAction(time.Now().UnixNano()) fmt.Fprintf(w, "hello\n") } func main() { http.HandleFunc("/hello", hello) log.Printf("start server on port 8090") http.ListenAndServe(":8090", nil) }
в цьому прикладі горутина перед викликом endLongtimeAction зайва
Приклад другий, використання горутини для простої дії
Є схожий на попередній приклад hello в якому можна розпаралелити AddView:
func hello(w http.ResponseWriter, r *http.Request) { go AddView(fontThemeID(), country(r)) fmt.Fprintf(w, "hello\n") }
import "sync" type FontThemeKey struct { FontThemeID uint8 Country string } type FontThemeValue struct { ViewCount uint32 RegisterCount uint32 } var ( fontThemeBuffer = make(map[FontThemeKey]FontThemeValue) fontThemeMutex sync.Mutex ) func AddView(fontThemeID uint8, country string) { var key = FontThemeKey{ FontThemeID: fontThemeID, Country: country, } fontThemeMutex.Lock() defer fontThemeMutex.Unlock() var value = fontThemeBuffer[key] value.ViewCount += 1 fontThemeBuffer[key] = value } func Flush() error { return store(swap()) } func swap() map[FontThemeKey]FontThemeValue { fontThemeMutex.Lock() defer fontThemeMutex.Unlock() var result = fontThemeBuffer fontThemeBuffer = make(map[FontThemeKey]FontThemeValue, len(result)) return result } func store(map[FontThemeKey]FontThemeValue) error { // store to stats return nil }
тепер зробимо простий тест щоб перевірити чи пришвидшує go швидкодію на простому прикладі:
import ( "sync/atomic" "testing" ) const ( fontThemeCount = 15 ) var ( fixtureCountries = []string{"C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8"} fixtureCountryLength = uint32(len(fixtureCountries)) ) func reset() { fontThemeBuffer = make(map[FontThemeKey]FontThemeValue) } func BenchmarkAddView(b *testing.B) { reset() var index uint32 b.RunParallel(func(pb *testing.PB) { for pb.Next() { var i = atomic.AddUint32(&index, 1) AddView(uint8(i%fontThemeCount), fixtureCountries[i%fixtureCountryLength]) } }) } func BenchmarkAddViewExtraGoroutine(b *testing.B) { reset() var index uint32 b.RunParallel(func(pb *testing.PB) { for pb.Next() { var i = atomic.AddUint32(&index, 1) // useless goroutine go AddView(uint8(i%fontThemeCount), fixtureCountries[i%fixtureCountryLength]) } }) }
Назва тесту | Кількість ітерацій | Середній час ітерації | Виділення пам’яті |
AddView | 6413756 | 185 ns/op | 0 B/op |
AddViewExtraGoroutine | 2628880 | 403 ns/op | 58 B/op |
Приклад третій, горутина за шаблоном
На сторінці продукту треба відобразити пару блоків, перший «рекомендації або схожі товари» та другий «разом з цим купують».Отримання цих блоків можна легко розпаралелити.
func ExtraGoodCodes(goodCode uint32) ([]uint32, []uint32) { var wg = new(sync.WaitGroup) var ( recommendations []uint32 supplies []uint32 ) wg.Add(1) go func() { recommendations = getRecommendationGoods(goodCode) wg.Done() }() wg.Add(1) go func() { supplies = getSupplyGoods(goodCode) wg.Done() }() wg.Wait() return recommendations, supplies }
func ExtraGoodCodes(goodCode uint32) ([]uint32, []uint32) { var wg = new(sync.WaitGroup) var ( recommendations []uint32 supplies []uint32 ) wg.Add(1) go func() { recommendations = getRecommendationGoods(goodCode) wg.Done() }() supplies = getSupplyGoods(goodCode) wg.Wait() return recommendations, supplies }
9 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів