-
Notifications
You must be signed in to change notification settings - Fork 177
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Perform optimization #139
base: master
Are you sure you want to change the base?
Perform optimization #139
Conversation
Some refactoring Update case-study.md
|
||
Вот как я построил `feedback_loop`: | ||
1) Использовал профилировщик `RubyProf Flat` с выключенным GC (по началу на объеме в 50к строк) | ||
2) Находил главную точку роста и начинал править ровно с этого места |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
1) Использовал профилировщик `RubyProf Flat` с выключенным GC (по началу на объеме в 50к строк) | ||
2) Находил главную точку роста и начинал править ровно с этого места | ||
3) Перезапускал профилировщик повторно и смотрел на полученный результат + непосредственно сам скрипт с включенным GC | ||
4) Увеличивал объем данных и повторно начинал с пункта 1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Плюсую увеличение объёма данных
Хоршо подбирать объём данных так, чтобы программа успевала покрутиться пару секунд. Если она завершается слишком быстро (“не успевает поработать”) могут возникнуть какие-то перекосы (например, на полном объёме основная часть времени тратится в основном цикле, а если данных мало - то большая часть уходит на инициализацию и финализацию, например на чтение из файла и запись потом в файл)
И плюс когда время уже на миллисекунды - больше влияние погрешностей.
user_sessions = sessions_grouped[user['id']] | ||
``` | ||
- На объеме данных в 50к строк скрипт работал +- 2 секунды | ||
- `Array#select` упал с 80% до 0% |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
И главное что асимптотика стало качественно лучше и приблизилась к линейной
sessions = sessions + [parse_session(line)] if cols[0] == 'session' | ||
end | ||
``` | ||
- На полном объёме данных выжирает всю оперативу, процесс убивается системой (видно в syslog). Переписал всю логику на использование массива объектов классов User и Session вместо хранения в виде массива строк |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Кек, но оно выжирает оперативку и убивается только с выключенным GC
|
||
### Ваша находка №5 | ||
- `RubyProf Flat` показывает большой % использования `Date#parse` | ||
- Обратив внимание на структуру данных, видно, что конструкцию `Date#parse` можно опустить вообще - использование `.sort.reverse' более чем достаточно |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 да, такая пасхалочка
1.000 i/100ms | ||
Calculating ------------------------------------- | ||
slow string concatenation | ||
0.034 (± 0.0%) i/s - 1.000 in 29.189983s |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
'longestSession' => -> (user) { user.sessions_time.max.to_s + ' min.' }, | ||
'browsers' => -> (user) { user.sessions_browsers }, | ||
'usedIE' => -> (user) { user.sessions_browsers.include? 'INTERNET EXPLORER' }, | ||
'alwaysUsedChrome' => -> (user) { user.sessions_browsers.split(',').uniq.all? { |b| b.upcase =~ /CHROME/ } }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
split по запятой как-то не очень, получается сначала собрали, потом разобрали
end | ||
|
||
report['usersStats'] = {} | ||
all_browsers = sessions_objects.map {|session| session.attributes['browser'].upcase}.sort.uniq.join(',') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
обратите внимание, что map создаёт массив, sort ещё один
collect_stats_from_users(report, users_objects) do |user| | ||
{ 'totalTime' => user.sessions.map {|s| s['time']}.map {|t| t.to_i}.sum.to_s + ' min.' } | ||
end | ||
report['uniqueBrowsersCount'] = all_browsers.split(',').size |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
опять собрали, разобрали
уникальные браузеры удобно собирать в Set, или SortedSet
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
No description provided.