Conversation
Some refactoring Update case-study.md
|
|
||
| Вот как я построил `feedback_loop`: | ||
| 1) Использовал профилировщик `RubyProf Flat` с выключенным GC (по началу на объеме в 50к строк) | ||
| 2) Находил главную точку роста и начинал править ровно с этого места |
| 1) Использовал профилировщик `RubyProf Flat` с выключенным GC (по началу на объеме в 50к строк) | ||
| 2) Находил главную точку роста и начинал править ровно с этого места | ||
| 3) Перезапускал профилировщик повторно и смотрел на полученный результат + непосредственно сам скрипт с включенным GC | ||
| 4) Увеличивал объем данных и повторно начинал с пункта 1) |
There was a problem hiding this comment.
Плюсую увеличение объёма данных
Хоршо подбирать объём данных так, чтобы программа успевала покрутиться пару секунд. Если она завершается слишком быстро (“не успевает поработать”) могут возникнуть какие-то перекосы (например, на полном объёме основная часть времени тратится в основном цикле, а если данных мало - то большая часть уходит на инициализацию и финализацию, например на чтение из файла и запись потом в файл)
И плюс когда время уже на миллисекунды - больше влияние погрешностей.
| user_sessions = sessions_grouped[user['id']] | ||
| ``` | ||
| - На объеме данных в 50к строк скрипт работал +- 2 секунды | ||
| - `Array#select` упал с 80% до 0% |
There was a problem hiding this comment.
И главное что асимптотика стало качественно лучше и приблизилась к линейной
| sessions = sessions + [parse_session(line)] if cols[0] == 'session' | ||
| end | ||
| ``` | ||
| - На полном объёме данных выжирает всю оперативу, процесс убивается системой (видно в syslog). Переписал всю логику на использование массива объектов классов User и Session вместо хранения в виде массива строк |
There was a problem hiding this comment.
Кек, но оно выжирает оперативку и убивается только с выключенным GC
|
|
||
| ### Ваша находка №5 | ||
| - `RubyProf Flat` показывает большой % использования `Date#parse` | ||
| - Обратив внимание на структуру данных, видно, что конструкцию `Date#parse` можно опустить вообще - использование `.sort.reverse' более чем достаточно |
| 1.000 i/100ms | ||
| Calculating ------------------------------------- | ||
| slow string concatenation | ||
| 0.034 (± 0.0%) i/s - 1.000 in 29.189983s |
| '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.
split по запятой как-то не очень, получается сначала собрали, потом разобрали
| end | ||
|
|
||
| report['usersStats'] = {} | ||
| all_browsers = sessions_objects.map {|session| session.attributes['browser'].upcase}.sort.uniq.join(',') |
There was a problem hiding this comment.
обратите внимание, что 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.
опять собрали, разобрали
уникальные браузеры удобно собирать в Set, или SortedSet
No description provided.