Как создать вектор RAWSXP из C char* ptr без перераспределения

Есть ли способ создать вектор RAWSXP, который поддерживается существующим C char* ptr.

Ниже я показываю свою текущую рабочую версию, которая требует перераспределения и копирования байтов, и вторую воображаемую версию, которой не существует.

          // My current slow solution that uses lots of memory
    SEXP getData() {
      // has size, and data
      Response resp = expensive_call();
    
      //COPY OVER BYTE BY BYTE
      SEXP respVec = Rf_allocVector(RAWSXP, resp.size);
      Rbyte* ptr = RAW(respVec);
      memcpy(ptr, resp.msg, resp.size);
    
      // free the memory
      free(resp.data);
    
      return respVec;
    }
    
    // My imagined solution
    SEXP getDataFast() {
      // has size, and data
      Response resp = expensive_call();
    
      // reuse the ptr
      SEXP respVec = Rf_allocVectorViaPtr(RAWSXP, resp.data, resp.size);
    
      return respVec;
    }

я тоже заметил Rf_allocVector3который, кажется, дает контроль над распределением памяти вектора, но я не мог заставить это работать. Это мой первый раз, когда я пишу расширение R, поэтому я думаю, что делаю что-то глупое. Я пытаюсь избежать копирования, так как данные будут около ГБ (очень большие, но разреженные матрицы).

1 ответ

Копирование более 1 ГБ занимает < 1 секунды. Если ваш звонок стоит дорого, это может быть предельная стоимость, которую вы должны профилировать, чтобы увидеть, действительно ли это узкое место.

Способ, которым вы пытаетесь что-то сделать, вероятно, невозможен, потому что откуда R узнает, как собирать данные мусором?

Но предполагая, что вы используете контейнеры STL, один изящный трюк, который я недавно видел , заключается в использовании второго аргумента шаблона контейнеров STL — распределителя.

      template<
    class T,
    class Allocator = std::allocator<T>
> class vector;

Общий план стратегии таков:

  1. Создайте собственный распределитель с использованием R-памяти, отвечающий всем требованиям (по сути, вам просто нужно allocateи deallocate)
  2. Каждый раз, когда вам нужно вернуть данные в R из контейнера STL, убедитесь, что вы инициализируете его с помощью своего собственного распределителя.
  3. При возврате данных извлеките базовые данные R, созданные вашим распределителем R-памяти — без копирования.

Этот подход дает вам всю гибкость контейнеров STL, используя только память, о которой знает R.

Другие вопросы по тегам