Conversation
araslanov-e
commented
Jan 26, 2025
- Оптимизировал программу для обработки больших данных менее 30 секунд
- Добавил тест производительности
- Описал этапы оптимизации
|
|
||
| def test_result | ||
| work(file_name: 'data.txt') | ||
| expected_result = '{"totalUsers":4,"uniqueBrowsersCount":14,"totalSessions":15,"allBrowsers":"CHROME 13,CHROME 20,CHROME 35,CHROME 6,FIREFOX 12,FIREFOX 32,FIREFOX 47,INTERNET EXPLORER 10,INTERNET EXPLORER 28,INTERNET EXPLORER 35,SAFARI 17,SAFARI 29,SAFARI 39,SAFARI 49","usersStats":{"Leida Cira":{"sessionsCount":6,"totalTime":"455 min.","longestSession":"118 min.","browsers":"FIREFOX 12, INTERNET EXPLORER 28, INTERNET EXPLORER 28, INTERNET EXPLORER 35, SAFARI 29, SAFARI 39","usedIE":true,"alwaysUsedChrome":false,"dates":["2017-09-27","2017-03-28","2017-02-27","2016-10-23","2016-09-15","2016-09-01"]},"Palmer Katrina":{"sessionsCount":5,"totalTime":"218 min.","longestSession":"116 min.","browsers":"CHROME 13, CHROME 6, FIREFOX 32, INTERNET EXPLORER 10, SAFARI 17","usedIE":true,"alwaysUsedChrome":false,"dates":["2017-04-29","2016-12-28","2016-12-20","2016-11-11","2016-10-21"]},"Gregory Santos":{"sessionsCount":4,"totalTime":"192 min.","longestSession":"85 min.","browsers":"CHROME 20, CHROME 35, FIREFOX 47, SAFARI 49","usedIE":false,"alwaysUsedChrome":false,"dates":["2018-09-21","2018-02-02","2017-05-22","2016-11-25"]},"Evgeny Araslanov":{"sessionsCount":0,"totalTime":"0 min.","longestSession":" min.","browsers":"","usedIE":false,"alwaysUsedChrome":true,"dates":[]}}}' + "\n" |
There was a problem hiding this comment.
Вспомнил момент, что тут баг есть, у "Evgeny Araslanov" нет сессий, но при этом в результате "alwaysUsedChrome":true
| config.include RSpec::Benchmark::Matchers | ||
| end | ||
|
|
||
| describe 'Performance' do |
There was a problem hiding this comment.
И тут ещё понял, что наверное стоит добавить в тест проверку кол-ва строк в файле data_large.txt, чтобы мы были уверены на каком количестве данных ожидаем такой результат
There was a problem hiding this comment.
ну в целом хорошо бы чтобы число строк было наглядно, да
| Программа поставлялась с тестом. Выполнение этого теста в фидбек-лупе позволяет не допустить изменения логики программы при оптимизации. | ||
|
|
||
| ## Feedback-Loop | ||
| Для того, чтобы иметь возможность быстро проверять гипотезы я выстроил эффективный `feedback-loop`, который позволил мне получать обратную связь по эффективности сделанных изменений за 10-20 секунд. |
| ## Feedback-Loop | ||
| Для того, чтобы иметь возможность быстро проверять гипотезы я выстроил эффективный `feedback-loop`, который позволил мне получать обратную связь по эффективности сделанных изменений за 10-20 секунд. | ||
|
|
||
| Вот как я построил `feedback_loop`: Создавал файл с N строк, чтобы программа могла выполнятся 10-20 секунд |
| ### Ваша находка №1 | ||
| - CallStack показал что программа 94.55% времени тратит на Array#select. С помощью Graph стало понятно что много времени тратиться на поиск сессий пользователя. | ||
| - Для решения данной проблемы, перед тем как проходится по пользователям, нужно подготовить данные users_sessions в виде хэша, ключем будет id пользователя, а значение массив его сессий, тогда мы один раз пройдемся по sessions | ||
| - Время выполнения программы уменьшилось с ~20 секунд до ~1 секунды, при входных данных в 30000 строк. Время выполнения программы на большом объёме данных больше 30 секунд. |
There was a problem hiding this comment.
тут самое главное, что асимптотику сильно лучше сделали
|
|
||
| ### Ваша находка №4 | ||
| - При объёме данных в 400к строк CallStack показал что программа 52.94% времени тратит на Array#all?. С помощью Graph стало понятно что много времени тратиться на проверку уникальности браузера (uniqueBrowsers). | ||
| - Для этих данных лучше всего подойдет Set. |
| config.include RSpec::Benchmark::Matchers | ||
| end | ||
|
|
||
| describe 'Performance' do |
There was a problem hiding this comment.
ну в целом хорошо бы чтобы число строк было наглядно, да
| collect_stats_from_users(report, users_objects) do |user| | ||
| { 'sessionsCount' => user.sessions.count } | ||
| end | ||
| progressbar.increment |
There was a problem hiding this comment.
progressbar сам по себе может довольно сильно тормозить, лучше делать его отключаемым / опциональным
| 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 | ||
| progressbar.increment |
There was a problem hiding this comment.
а, тут progressbar не по кол-ву юзеров/строк, а по кол-ву этапов программы
можно и так для красоты, либо просто путсами