Как избежать копирования больших объектов в R - функция get () создает копию? - PullRequest
0 голосов
/ 30 мая 2019

У меня есть унаследованный код R, который использует идиому, чтобы избежать копирования больших фреймов данных. Когда функция, которая строит фрейм данных, завершает свою работу, она не возвращает фрейм данных, а сохраняет ее в глобальном контексте среды:

assign(df_name, df, envir = globalenv())

После завершения функции вызывающий код извлекает фрейм данных следующим образом:

df <- get(df_name, envir = globalenv())

Мой вопрос таков: действительно ли сама функция get() делает копию, когда возвращает значение, создавая, таким образом, ту самую копию, которой эта идиома должна была избежать? Если так, есть ли лучший способ сделать это?

Ответы [ 3 ]

3 голосов
/ 30 мая 2019

Насколько я знаю, возвращение чего-либо на самом деле не копирует его из одной ячейки памяти в другую.Пара тестов:

trace_return <- function() {
  df <- data.frame(a = 1:10, b = letters[1:10])
  print(tracemem(df))
  df
}

ans <- trace_return()
# "<00000188C114D578>"
ans$a[1L] <- 0L # copy triggered on modify
# tracemem[0x00000188c114d578 -> 0x00000188c10ab098]: 
# tracemem[0x00000188c10ab098 -> 0x00000188c10ab258]: $<-.data.frame $<- 
# tracemem[0x00000188c10ab258 -> 0x00000188c10ab358]: $<-.data.frame $<-

И:

e <- new.env()
e$ans <- trace_return()
# "<00000188C13F8EF8>"
ans <- e$ans # no copy here
ans$b <- NULL
# tracemem[0x00000188c13f8ef8 -> 0x00000188c14293f8]: 
# tracemem[0x00000188c14293f8 -> 0x00000188c1429378]: $<-.data.frame $<- 
# tracemem[0x00000188c1429378 -> 0x00000188c1429278]: $<-.data.frame $<- 
3 голосов
/ 30 мая 2019

Одним словом, это чепуха.Что делает копии здесь - это два назначения (оба через assign и <-).Простое возвращение объекта из функции позволило бы сохранить одну из копий.

Кстати, само копирование стоит дешево , поскольку R реализует концепцию, называемую " копирование при записи * 1010".* ”Семантика: вышеприведенные команды логически делают копии, но физически это только увеличивает счетчик ссылок внутри скопированной ссылки.Фактические данные за ссылкой копируются только при изменении данных с помощью одной из ссылок.

0 голосов
/ 30 мая 2019

Неважно, есть ли две копии идентичного data.frame. Но, честно говоря, я не вижу смысла назначать data.frame дважды.

Вы можете использовать пакет pryr, чтобы увидеть, сколько памяти выделяет объект.

library(pryr)

df <- do.call(data.frame, replicate(8000, rep(FALSE, 8000), simplify=FALSE))

assign("dname_out", df, envir = globalenv())

mem_used()
337 MB

mem_change(df <- get("dname_out", envir = globalenv()))

736 B

> mem_used()
337 MB

Изменение в памяти составляет всего 736 байт, так что на самом деле вы не можете разбить ваш компьютер, создав тонны копий.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...