Вам не вистачає швидкості R? Шукаємо приховані резерви

Іноді доводиться стикатися з переконанням, що 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++ модулі.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.