Как стать автором
Обновить

Вам не хватает скорости R? Ищем скрытые резервы

Время на прочтение3 мин
Количество просмотров5.4K

Иногда приходится сталкиваться с убеждением, что R, будучи интерпретатором, слишком медленный для анализа задач «быстрого» бизнеса. В большинстве случаев такие тезисы поступают от аналитиков, не обладающих опытом разработки серьезного ПО, в т.ч. высокопроизводительных или встроенных систем, крайне требовательных к ограниченным аппаратным ресурсам. Это совершенно нормально, никто не может знать все на свете. однако, в 95% случаев оказывается, что R совершенно ни при чем, проблема заключается в неэффективном управлении памятью и процессом вычисления.


Ровно поэтому в настоящей заметке будут затронуты 5 важных моментов (можно назвать и 6 и 10, но пусть будет 5), работа над которыми очень часто помогает преобразить медленный код. Запись, скорее, реферативная и в приземлении на R, поскольку сами принципы давно известны. "Шпаргалка" для начала исследований по возможной оптимизации существующего кода.


  1. Все расчетные данные должны быть в оперативной памяти.


  2. Все инварианты по отношению к переменным цикла должны вычисляться за пределами цикла.


  3. Используйте копирование объектов эффективно.


  4. Следите за структурой объектов, чистите мусор.


  5. Оптимизируйте с умом.

Теперь по шагам.


Все в оперативной памяти


Не занимайтесь «просто» обработкой данных. Проанализируйте задачу, посчитайте объемы данных с которыми работаете, посмотрите, как можно разделить данные на автономные блоки данных, соразмерные доступной вам оперативной памяти. Можно эти блоки обсчитывать последовательно, а можно можно, если есть такая возможность, распараллелить работу над каждым независимым блоком, («Map — Reduce»). Своп на диск — просаживание в производительности на несколько порядков.


«Выносите за скобки»


Простое алгебраическое свойство дистрибутивности актуально для циклических вычислений как никогда. Любые вычисления, явные или скрытые в функциональном подходе, которые никак не завязаны на индекс цикла, должны быть вынесены за пределы цикла. Любые долго вычисляемые значения, которые используются несколько раз крайне желательно вынести за рамки основного тела программы и далее фигурировать в виде табличных значений. Длинный цикл из нескольких дополнительных микросекунд может сделать минуты-часы-сутки.


Следите за копированием


В языках высокого уровня за каждым объектом\переменной могут скрываться достаточно сложные структуры, содержащие массу дополнительной служебной и мета информации. И тогда простая процедура выполнения операции над объектом, наподобие такой:


t <- f(t, n)

может привести к динамическому выделению памяти и копированию далеко не одного десятка байт. Будучи помещенным в цикл, такая процедура может съесть любую частоту любого процессора и попросить еще.


Выбрасывайте мусор


Берегите оперативную память. Использовали объект и больше он вам не нужен? Удалите вручную, не дожидайтесь работы мусорщика. Можете и не дождаться.


Посчитали регрессию и нужна только таблица значений? А вы знаете сколько весит lm объект и что там лишнего?
В качестве примера запись из блога: «Reducing your R memory footprint by 7000x»


А вы уверены, что применяете функции эффективно? Знаете, как они устроены? Вот еще интересный пример:


t <- raw.df$timestamp
object.size(t) # имеем на входе 130 кб
m <- lapply(t, function(x){round(x, units="hours")}) # так из 130 кб получаем 35 Мб
m <- lapply(t, function(x){round_date(x, unit = "hour")}) # тут получаем 8Мб !!!
m <- round_date(t, unit = "hour") # 130 кб, самый быстрый и компактный вариант

Если дальше работать с этим объектом m не только на чтение, что будет быстрее обрабатывать 130кб или 35Мб? По-моему, ответ вполне очевиден.


Оптимизация кода


Если код исполняется медленно, посмотрите профайл исполнения. Найдите узкие места и оптимизируйте именно их. Не тратьте время на оптимизацию некритичных узлов.


И не забываем высказывание великого ученого: "The real problem is that programmers have spent far too much time worrying about efficiency in the wrong places and at the wrong times; premature optimization is the root of all evil (or at least most of it) in programming." — Дональд Кнут, лекция «Computer Programming as an Art», напечатанная в сборнике «Communications of the ACM» (Vol. 17, Issue 12, декабрь 1974, стр. 671)


Полезные ссылки с рекомендациями по отладке и профилировке.



Заключение


Практика неизбежно показывает, что эти нехитрые рекомендации очень часто помогают многократно ускорить код просто путем небольшой модификации, без дорогой модернизации железа, перехода на параллельные вычисления со сложной оркестровкой или выноса части вычислительных функций в C\C++ модули.


Предыдущий пост: "Применение R для работы с утверждением «Кто виноват? Конечно ИТ!»"
Следующий пост: "Запрягаем R на службу бизнесу на «1-2-3»"

Теги:
Хабы:
+6
Комментарии11

Публикации

Истории

Работа

Data Scientist
63 вакансии

Ближайшие события

Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн