Эффективный способ хранения большого количества символьных данных между транзакциями в C ++ - PullRequest
0 голосов
/ 06 января 2020

Для нашего приложения у нас есть следующий сценарий:

Во-первых, мы получаем большой объем данных (в некоторых случаях это может быть больше 100 МБ) через сторонний API в наш класс через конструктор, как:

class DataInputer
{
public:
    DataInputer(int id, const std::string& data) : m_id(id), m_data(data) {}
    int handle() { /* Do some stuff */ } 
private:
    std::string m_id;
    std::string m_data;
};

Цепочка вызовов, идущая в наш класс DataInputer выглядит следующим образом:

int dataInputHandler()
{
    std::string inputStringFromThirdParty = GiveMeStringFrom3rdPartyMagic(); // <- 1.
    int inputIntFromThirdParty = GiveMeIntFrom3rdPartyMagic();

    return DataInputer(inputIntFromThirdParty, inputDataFromThirdParty).handle();
}

У нас есть некоторый контроль над тем, как dataInputHandler обрабатывает свою строку (отмечена строка с 1. - это место, где строка создается как фактический объект), но нет контроля над тем, что на самом деле GiveMeStringFrom3rdPartyMagic использует для ее предоставления (если это важно для кого-то, эти данные откуда-то поступают через подключение к сети) так что нам нужно. В качестве утешения мы имеем полный контроль над классом DataInputer.

Теперь, что якобы приложение делает, чтобы удерживать строку и связанный с ней целочисленный идентификатор до более поздней точки, когда оно может быть отправлено другому компонент (через другое сетевое соединение), при условии, что компонент предоставляет действительный идентификатор (это краткое описание). Проблема в том, что мы не можем (не хотим) делать это в методе handle класса DataInputer, он блокирует его на неизвестное время.

В качестве элементарного решения, мы думали о создании хранилища строк «в памяти» для всех различных строк, которые будут поступать от всех различных сетевых клиентов, где нижняя строка состоит из:

std::map<int, std::string> idStringStore;

, где int идентифицирует id строки, string на самом деле является данными, а DataInputer::handle делает что-то вроде idStringStore.emplace(m_id, m_data);:

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

Важное замечание: мы связаны с C + +11 на данный момент: (

1 Ответ

0 голосов
/ 06 января 2020

Используйте семантику перемещения для передачи сторонних данных в ваш DataInputer конструктор. std::move здесь избыточен, но проясняет намерение читателя:

class DataInputer
{
public:
    DataInputer(int id, std::string&& data) : m_id(id), m_data(std::move(data)) {}
    int handle() { /* Do some stuff */ } 
private:
    std::string m_id;
    std::string m_data;
};

И передает GiveMeStringFrom3rdPartyMagic() напрямую в качестве аргумента конструктору без предварительного копирования в inputStringFromThirdParty.

int dataInputHandler()
{
    int inputIntFromThirdParty = GiveMeIntFrom3rdPartyMagic();

    return DataInputer(inputIntFromThirdParty, GiveMeStringFrom3rdPartyMagic()).handle();
}

Конечно, вы можете использовать std::map или любой другой контейнер STL, который поддерживает семантику перемещения. Дело в том, что семантика перемещения, как правило, это то, что вы хотите использовать, чтобы избежать ненужных копий.

...