Консольные приложения на Go

13,432 views

Published on

Доклад с Golang Meetup 24.07.2014

Published in: Engineering
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
13,432
On SlideShare
0
From Embeds
0
Number of Embeds
10,987
Actions
Shares
0
Downloads
12
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Консольные приложения на Go

  1. 1. Консольные приложения на Go Андрей Смирнов, Go Meetup July 2014
  2. 2. aptly • Система управления репозиториями Debian- пакетов • Зеркалирование репозиториев, управление репозиториями своих пакетов • Создание snapshotов репозиториев, слияние, перемещение пакетов • Публикация как Debian-репозиториев
  3. 3. Почему Go? • Fun! • Большие объемы метаданных (30Мб/архитектура) • Статическая компиляция • Отличная HTTP-библиотека • Там нет genericов? (контейнеры)
  4. 4. Как вышло • Отличный набор библиотек (всех!) • Высокая производительность • Аккуратно работать с памятью • Язык позволяет правильно структурировать программу
  5. 5. Параллельный
 download
  6. 6. Задача • Скачивать файлы в несколько потоков (асинхронно) • Скачивать файл и ожидать результата
  7. 7. Скачиватель channel: queue Worker 1
 (goroutine) Worker 2
 (goroutine) Worker 3
 (goroutine) Worker 4
 (goroutine)
  8. 8. Возврат результата func (d *Downloader) Download(url, destination string) error !
  9. 9. Возврат результата func (d *Downloader) Download(url, destination string) error ! ! func (d *Downloader) Download(url, destination string) <-chan error ! !
  10. 10. Возврат результата func (d *Downloader) Download(url, destination string) error ! ! func (d *Downloader) Download(url, destination string) <-chan error ! ! func (d *Downloader) Download(url, destination string, result chan<- error)
  11. 11. Синхронный вариант func (d *Downloader) DownloadWait(url, destination string) error { ch := make(chan error) d.Download(url, destination, ch) return <-ch }
  12. 12. Скачивание по списку list := ... ! results := make(chan error, len(list)) ! for _, l := range list { d.Download(l.url, l.destination, results) } ! for i := 0; i < len(list); i++ { err := <-results if err != nil { fmt.Printf("Download error: %sn") } }
  13. 13. Приостановкаfunc NewDownloader(N int) *Downloader {! ! return &Downloader{! ! ! queue: make(chan *Task, 1000),! ! ! pause: make(chan struct{}),! ! ! unpause: make(chan struct{}),! ! ! threads: N,! ! }! }! ! func (downloader *Downloader) Pause() {! ! for i := 0; i < downloader.threads; i++ {! ! ! downloader.pause <- struct{}{}! ! }! }! ! ! ! for i := 0; i < downloader.threads; i++ {! ! ! go func() {! ! ! ! for {! ! ! ! ! select {! ! ! ! ! case <-downloader.pause:! ! ! ! ! ! <-downloader.unpause! ! ! ! ! case task := <-downloader.queue:! ! ! ! ! ! downloader.handleTask(task)! ! ! ! ! }! ! ! ! }! ! ! }()! ! }!
  14. 14. Прогресс
  15. 15. Прогресс
  16. 16. Архитектура ProgressBar
 atomic N 200 msredraw goroutine pb goroutine main update update update
  17. 17. Архитектура ProgressBar
 atomic N 200 msredraw goroutine pb goroutine main update update update channel goroutine console write to stdout
  18. 18. io.MultiWriter ! resp, err = http.Get(url) outfile, err = os.Create(destination) _, err = io.Copy(outfile, resp.Body)
  19. 19. io.MultiWriter ! resp, err = http.Get(url) outfile, err = os.Create(destination) _, err = io.Copy(outfile, resp.Body) resp, err = http.Get(task.url) outfile, err = os.Create(temppath) ! _, err = io.Copy( io.MultiWriter(outfile, progressbar), resp.Body)
  20. 20. Writer type Writer interface { Write(p []byte) (n int, err error) } ! func (p* ProgressBar) Increment(n int) { ... } ! func (p* ProgressBar) Write(p []byte) (n int, err error) { n = len(p) p.Increment(n) return }
  21. 21. CheckSummer type ChecksumWriter struct { hashes []hash.Hash } ! func NewChecksumWriter() *ChecksumWriter { return &ChecksumWriter{ hashes: []hash.Hash{md5.New(), sha1.New(), sha256.New()}, } } ! func (c *ChecksumWriter) Write(p []byte) (n int, err error) { for _, h := range c.hashes { h.Write(p) } ! return len(p), nil }
  22. 22. Ограничение скорости • Задача: ограничить общую скорость скачивания flow = flowcontrol.NewWriter(downloadLimit) ! ... ! _, err = io.Copy( io.MutliWriter(outfile, flow, progress, checksummer), resp)
  23. 23. Вложенные команды • Или история и о первом pull request в aptly • Что получилось: • aptly mirror create … • aptly mirror list • aptly snapshot create from mirror …
  24. 24. commander • Простой способ создавать подкоманды • История про первый pull-request или версионирование библиотек Go • Большое количество патчей • Альтернатива (лучше!) - cobra
  25. 25. GC • mark-and-sweep • precise (1.3), parallel, concurrent sweep (1.3)
  26. 26. aptly • Обновление зеркала репозитория • Парсинг мета-информации о пакетах, обработка, сохранение в БД • 40Мб/архитектура • При создании зеркала используется 800Мб памяти! 😭
  27. 27. Анализ • runtime-статистика об использовании кучи • runtime.ReadMemStats(): • HeapSys • HeapAlloc • HeapIdle
  28. 28. Что делать? • Долго работающие функции: освобождать ненужные объекты (x = nil) • Повторное использование объектов вместо выделения новых
  29. 29. Было func (p *Package) Encode() []byte {! var buf bytes.Buffer! ! encoder := codec.NewEncoder(&buf, &codec.MsgpackHandle{})! encoder.Encode(p)! ! return buf.Bytes()! }!
  30. 30. Стало var (! ! encodeBuf bytes.Buffer! ! codecHandle = &codec.MsgpackHandle{}! )! ! func (p *Package) Encode() []byte {! ! encodeBuf.Reset()! ! ! encoder := codec.NewEncoder(&encodeBuf, codecHandle)! ! encoder.Encode(p)! ! ! return encodeBuf.Bytes()! }!
  31. 31. А что дальше? • Профилируем программу по памяти и процессору • (Много думаем) • Придумываем решение!
  32. 32. Сборка и релиз • aptly - кроссплатформенный инструмент • Статическая компиляция • go cross compiling • Запуск системных тестов
  33. 33. Решение “в лоб” • Виртуалки CentOS/Debian/FreeBSD/32/64 • Сборка: установим go с помощью gvm • Запуск системных тестов на каждой платформе • Распространение: просто скачать исполняемый файл
  34. 34. Создание пакетов ОС • Сложно упаковать “корректно” со всеми зависимостями • “Бинарные” пакеты: fpm
  35. 35. Контейнеры • Фобия? (Страх до начала разработки) • Slices + package sort = 90% решений • В реальность модуль из 141 строки с общими операциями над []string • Сложные алгоритмы не выражаются в терминах genericов • Шанс на микрооптимизацию
  36. 36. Вопросы? • @smira • me@smira.ru • Skype: smirnov.andrey • http://smira.ru/
  37. 37. Ссылки • aptly: github.com/smira/aptly • ProgressBar: github.com/cheggaaa/pb • flowcontrol: code.google.com/p/mxk/go1/ flowcontrol • commander: github.com/gonuts/commander • cobra: github.com/spf13/cobra

×