R:Оптимизация/Компиляция в байт-код — различия между версиями
м (→Компиляция функций и выражений) |
м (→Компиляция функций и выражений) |
||
Строка 64: | Строка 64: | ||
{{r-code|code=<nowiki>> la1c <- cmpfun(la1) | {{r-code|code=<nowiki>> la1c <- cmpfun(la1) | ||
> la2c <- cmpfun(la2) | > la2c <- cmpfun(la2) | ||
− | > lapplyc <- | + | > lapplyc <- cmpfun(lapply)</nowiki>}} |
+ | |||
+ | Сравним производительность этих функций: | ||
+ | |||
+ | {{r-code|code=<nowiki>> microbenchmark(lapply(x, is.null), la1(x, is.null), la2(x, is.null), | ||
+ | + lapplyc(x, is.null), la1c(x, is.null), la2c(x, is.null)) | ||
+ | Unit: microseconds | ||
+ | expr min lq median uq max neval | ||
+ | lapply(x, is.null) 174.1 181.2 196.4 229.5 946 100 | ||
+ | la1(x, is.null) 786.0 816.2 838.6 985.6 1812 100 | ||
+ | la2(x, is.null) 967.6 996.9 1085.8 1359.9 2417 100 | ||
+ | lapplyc(x, is.null) 173.4 181.1 196.8 214.7 333 100 | ||
+ | la1c(x, is.null) 392.0 409.8 433.8 502.3 1400 100 | ||
+ | la2c(x, is.null) 403.6 415.6 439.7 532.1 1361 100</nowiki>}} | ||
+ | |||
+ | Обращается на себя внимание, что скомпилированная версия функции <code>lapply()</code> не превосходит по производительности оригинальную версию. | ||
== Компиляция скриптов == | == Компиляция скриптов == |
Версия 13:15, 4 мая 2014
|
Материал «R:Оптимизация/Компиляция в байт-код», созданный автором Артём Клевцов, публикуется на условиях лицензии Creative Commons «Attribution» («Атрибуция») 4.0 Всемирная. | |
|
Перед использованием функций из пакетов их необходимо предварительно установить и загрузить: КодR <syntaxhighlight lang="r">> install.packages(pkgs = "pkgname") > library(package = "pkgname")</syntaxhighlight> |
В данном материале рассматривается один из способов ускорения выполнения кода путём компиляции в байт-код. Байт-код - машинно-независимый код низкого уровня, генерируемый транслятором и исполняемый интерпретатором. Большинство инструкций байт-кода эквивалентны одной или нескольким командам ассемблера. Трансляция в байт-код занимает промежуточное положение между компиляцией в машинный код и интерпретацией.
Программа на байт-коде обычно выполняется интерпретатором байт-кода (обычно он называется виртуальной машиной, поскольку подобен компьютеру). Преимущество - в портируемости, т. е. один и тот же байт-код может исполняться на разных платформах и архитектурах. То же самое преимущество дают интерпретируемые языки. Однако, поскольку байт-код обычно менее абстрактный, более компактный и более «компьютерный», чем исходный код, эффективность байт-кода обычно выше, чем чистая интерпретация исходного кода, предназначенного для правки человеком.
В составе базовых пакетов R поставляется пакет compiler
, который входит состав ядра R, но не загружается по умолчанию при старте R-сессии. Данный пакет включает в себя ряд функций для компиляции R-кода в байт-код.
Содержание
Параметры компиляции
Все рассмотренные ранее функции из пакета compiler
имеют опции, которые могут быть переданы в качестве аргументов функциям компиляции (аргумент options
), или заданы глобально с помощью функции setCompilerOptions()
.
Рассмотрим эти опции:
-
optimize
--- определяет уровень оптимизации: принимает значения от 0 до 3 (по умолчанию 2); -
suppressAll
--- управляет сообщениями: принимает значенияTRUE
илиFALSE
(по умолчанию code>FALSE</code>); -
suppressUndefined
--- управление сообщения о неопределённых (undefined) переменных: может принимать значенияTRUE
или список имён переменных (по умолчанию ".Generic", .Method", ".Random.seed", ".self").
Получить текущее значение глобальных опций компиляции можно с помощью функции getCompilerOption()
:
<syntaxhighlight lang="r">> getCompilerOption("optimize") [1] 2 > getCompilerOption("suppressAll") [1] FALSE > getCompilerOption("suppressUndefined") [1] ".Generic" ".Method" ".Random.seed" ".self"</syntaxhighlight>
Компиляция функций и выражений
Компиляция функций осуществляется с помощью функции cmpfun()
. Возьмём пример из документации к функции cmpfun()
, вкотором предлагается сравнить производительность различных реализаций функции lapply()
, а также их скомпилированных версий:
<syntaxhighlight lang="r"># old R version of lapply la1 <- function(X, FUN, ...) { FUN <- match.fun(FUN) if (!is.list(X)) X <- as.list(X) rval <- vector("list", length(X)) for(i in seq(along = X)) rval[i] <- list(FUN(X[[i]], ...)) names(rval) <- names(X) # keep `names' ! return(rval) } # a small variation la2 <- function(X, FUN, ...) { FUN <- match.fun(FUN) if (!is.list(X)) X <- as.list(X) rval <- vector("list", length(X)) for(i in seq(along = X)) { v <- FUN(X[[i]], ...) if (is.null(v)) rval[i] <- list(v) else rval[[i]] <- v } names(rval) <- names(X) # keep `names' ! return(rval) }</syntaxhighlight>
Скомпилируем эти функции в бат-код:
<syntaxhighlight lang="r">> la1c <- cmpfun(la1) > la2c <- cmpfun(la2) > lapplyc <- cmpfun(lapply)</syntaxhighlight>
Сравним производительность этих функций:
<syntaxhighlight lang="r">> microbenchmark(lapply(x, is.null), la1(x, is.null), la2(x, is.null), + lapplyc(x, is.null), la1c(x, is.null), la2c(x, is.null)) Unit: microseconds expr min lq median uq max neval lapply(x, is.null) 174.1 181.2 196.4 229.5 946 100 la1(x, is.null) 786.0 816.2 838.6 985.6 1812 100 la2(x, is.null) 967.6 996.9 1085.8 1359.9 2417 100 lapplyc(x, is.null) 173.4 181.1 196.8 214.7 333 100 la1c(x, is.null) 392.0 409.8 433.8 502.3 1400 100 la2c(x, is.null) 403.6 415.6 439.7 532.1 1361 100</syntaxhighlight>
Обращается на себя внимание, что скомпилированная версия функции lapply()
не превосходит по производительности оригинальную версию.
Компиляция скриптов
Ещё одна возможность, предоставляемая пакетом compiler
- это компиляция R-скриптов. Создание скомпилированных файлов осуществляется с помощью функции \texttt{cmpfile()}, а загрузка скомпилированных файлов с помощью функции loadcmp()
. Если выходной файл не указан, то выходной файл имеет тоже имя, что и входной, но с расширением .Rc
. Пример использования:
<syntaxhighlight lang="r">> cmpfile("script.R", "script.Rc") > loadcmp("script.Rc")</syntaxhighlight>