Comments 21
- Не совсем понятно — у вас приведенная горутина (To complete report processing even after return on timeout) вызывается в каком-то цикле, что утечка накапливается?
- Обычно после «получения» сигнала программа так или иначе завершается, поэтому примеры кода в документации приведены на этот самый простой распространенный кейс.
- Как правило, сигналы «ловят» на уровне main или близком к нему — в функцию обычно передают и работают с контекстом (context.Context).
- Вместо
done <- struct{}{}
в большинстве случаем можно и принято использоватьclose(done)
.
- Конечно. И по п.2 статьи можно оценить интенсивность (известно число провисших объектов и примерное время).
- Да. Но чтобы завершиться, неплохо бы корректно закрыть запущенные (форки, треды, корутины, горутины) нужное подчеркнуть. В go мне показалось проще подписаться на готовую сигнализацию «os.Signal». Я не прав? → п.3
- Ага, спасибо. Раз «так принято», есть смысл в дальнейшем перестроиться (чтобы не мешать сопровождающим код).
- Спасибо. Так действительно будет лучше читаться.
Если программа завершает работу, то какими-то завершающими действиями можно пренебречь, если они не влияют на результат. Например, csv writer лучше всё-таки зафлашить, а соответствующий открытый файл закрыть. Но конкретно с сигналами я никогда не видел код, который бы явно вызывал Stop имено для того, чтобы устранить утечку, потому что все равно программа тут же закрывается.
С контекстом было бы примерно так:
С контекстом было бы примерно так:
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
signals := make(chan os.Signal, 1)
signal.Notify(signals, syscall.SIGHUP, syscall.SIGINT, syscall.SIGKILL, syscall.SIGTERM)
go func() {
<-signals
fmt.Println("cancel")
cancel()
}()
done := make(chan struct{})
go func() {
for {
select {
case <-ctx.Done():
close(done)
return
}
}
}()
<-done
fmt.Println("exit")
}
Не вижу приемуществ от использования контекстов, кроме замены
case exitSignal = <-signals: на case <-ctx.Done():
Вот если спрятать логику чтобы была отдельная функция
case exitSignal = <-signals: на case <-ctx.Done():
Вот если спрятать логику чтобы была отдельная функция
func doYourStuff(ctx context.Context) <-chan struct{} {
done := make(chan struct{})
go func() {
for {
select {
case <-ctx.Done():
close(done)
return
}
}
}()
return done
}
«Самопальный» timer возможно тоже стоит заменить на context.WitdDeadline() или context.WithTimeout()
Почему бы и нет, раз есть готовое. Вопрос кругозора пишущего код.
- Вот Вы мне его (кругозора) и добавили. Хотя, есть нюанс. Если велосипед не тяжёлый, бывает смысл его реализовать без привлечения большого комбайна. В целях, так сказать, неувеличения энтропии. У меня вот там два типа сигнализации: тик и таймаут. Не думаю, что привлечение «context» сильно разгрузит код.
Не вникал в код, но мне кажется, вам бы подошли стандартные Ticker и Timer. При этом это были бы локальные объекты для вашей горутины, и не нужно было бы использовать глобальную синхронизируемую коллекцию таймеров.
Для устранения «недочетов» оформления кода и вообще на этапе ознакомления с языком можно использовать возможности IDE — например, GoLand (хотя он платный, но есть EAP/trial).
В дополнение к проверкам IDE есть линтеры. github.com/golangci/golangci-lint включает большой их набор, но по-умолчанию включены не все.
Для устранения «недочетов» оформления кода и вообще на этапе ознакомления с языком можно использовать возможности IDE — например, GoLand (хотя он платный, но есть EAP/trial).
В дополнение к проверкам IDE есть линтеры. github.com/golangci/golangci-lint включает большой их набор, но по-умолчанию включены не все.
С контекстами есть такая проблема, что они не дают возможности управлять порядком завершения компонентов, а также отследить момент, когда они все успешно завершаться. Примерно как если бы вы заглянули в комнату, крикнули «эй, завершитесь!», и пошли дальше, не интересуясь, что там дальше будет (ломанутся ли они все вместе одновременно в дверь, начав конфликтовать, очнутся ли только через сутки и тд и тп).
Я не так давно писал статью об том, как это делать: habr.com/ru/company/vivid_money/blog/531822
Думаю, вы сможете переиспользовать какие-то паттерны из последнего рассмотренного мной подхода.
Я не так давно писал статью об том, как это делать: habr.com/ru/company/vivid_money/blog/531822
Думаю, вы сможете переиспользовать какие-то паттерны из последнего рассмотренного мной подхода.
2. Использовать close(done) не просто удобно, но и в таких случаях не произойдет возможной утечки памяти. И скорее всего вам нужен defer close(done) в начале функции. Это обычный паттерн когда «producer» рутина работает с каналами.
Так и не понял была ли утечка связанная с commands.UUID или нет. «Вроде бы так можно, т.к. в этот момент переменная не „зачищена“ и должна быть скопирована в defer.».
Не очень понимаю что значит «зачищена», но вроде бы в таких случаях переменная будет аллоцирована в heap и код прозрачно для вас будет работать с указателем. Как и в случаях когда переменная утекает из функции
Так и не понял была ли утечка связанная с commands.UUID или нет. «Вроде бы так можно, т.к. в этот момент переменная не „зачищена“ и должна быть скопирована в defer.».
Не очень понимаю что значит «зачищена», но вроде бы в таких случаях переменная будет аллоцирована в heap и код прозрачно для вас будет работать с указателем. Как и в случаях когда переменная утекает из функции
func () {
v := 0
return &v
}
Я, когда утверждал «Вроде бы так можно», руководствовался вот этим (но «по памяти», отсюда prepend «Вроде»):
Я это понимаю как «любой defer создаёт функцию с аргументами, вычисляемыми (в данном случае, копируемыми) в момент задания (а не исполнения) defer». Поправьте, если у Вас другая версия реальности.
Это не отменяет «мутности» данного кода, и так по моему мнению делать просто не нужно. Ну вот зачем изображать «асинхронное замыкание» на языке, всячески поощряющем «деревянное» программирование? Для скорости? Так defer сам по себе «дорогой».
Each time the «defer» statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function is not invoked.
Я это понимаю как «любой defer создаёт функцию с аргументами, вычисляемыми (в данном случае, копируемыми) в момент задания (а не исполнения) defer». Поправьте, если у Вас другая версия реальности.
Это не отменяет «мутности» данного кода, и так по моему мнению делать просто не нужно. Ну вот зачем изображать «асинхронное замыкание» на языке, всячески поощряющем «деревянное» программирование? Для скорости? Так defer сам по себе «дорогой».
Запись в «занулённый» канал из ранее запущенной goroutine (завешивает «навечно» функцию со всеми объектами).
Я бы порекомендовал книжку Concurrency in Go.
В это трудно поверить, но надо признаться, что мне… как-то всё равно. Обзываю, как на язык ляжет.
- Удлинение слишком короткого слова — обычная у китайцев практика. Возможно, от них и пошло́.
С го это чуть более оправданно, потому что слово слишком короткое и очень часто используется, и просто в разговорной речи и в названиях продуктов (pokemon go, amazon go, тд) в итоге что-то гуглить становится очень сложно. Пусть лучше уж golang, это более уникальное слово, сразу задаётся нужный контекст.
ну, чего ты докопался, в самом деле?
> А так, наберите в Гугле Go, удивитесь, что он выдаст ссылки именно по Go
Вы же понимаете, что он выдаст вам ссылки именно по го, потому что вы скорее всего гуглили уже кучу программерских вещей и поэтому гугл догадывается, какой контекст вы ищете?
Думаю также, что с C или R тоже есть свои сложности, а также нет ничего плохого в том, чтобы называть язык так, как хочется, тем более, что это задаёт дополнительный контекст.
И да, кстати, домены для языков тоже называются golang.org и www.rust-lang.org вместо каких-нибудь go.it и rust.tech :)
Вы же понимаете, что он выдаст вам ссылки именно по го, потому что вы скорее всего гуглили уже кучу программерских вещей и поэтому гугл догадывается, какой контекст вы ищете?
Думаю также, что с C или R тоже есть свои сложности, а также нет ничего плохого в том, чтобы называть язык так, как хочется, тем более, что это задаёт дополнительный контекст.
И да, кстати, домены для языков тоже называются golang.org и www.rust-lang.org вместо каких-нибудь go.it и rust.tech :)
Ура, опять видны все комментарии. Вчера во второй половине дня с хабром случилось нечто, «подрезавшее» всё кроме первых нескольких. Вероятно, в отдаваемом мне шарде. (С нескольких точек/браузеров показывало одну и ту же «фигу», хотя число в заголовке было похоже на правду.)
А я уже́ было приготовился «вытаскивать» из почты. Потому что толковые (а даже если не очень) замечания — мой «профит» от подготовленного материала.
Всех с наступающим! Пора готовиться к НГ.
А я уже́ было приготовился «вытаскивать» из почты. Потому что толковые (а даже если не очень) замечания — мой «профит» от подготовленного материала.
Всех с наступающим! Пора готовиться к НГ.
Sign up to leave a comment.
pprof в golang: Исправляем утечку памяти