Как использовать {fmt} с большими даннымиC++

Программы на C++. Форум разработчиков
Ответить Пред. темаСлед. тема
Anonymous
 Как использовать {fmt} с большими данными

Сообщение Anonymous »

Я начинаю экспериментировать с {fmt} и написал небольшую программу, чтобы посмотреть, как она обрабатывает большие контейнеры. Казалось бы, функция fmt::print() (которая в конечном итоге отправляет вывод на стандартный вывод) внутренне сначала компонует весь результат в виде строки. Приведенная ниже тестовая программа, в которой я форматирую вектор размером 10 000 000, используя строку формата, которая занимает 100 байт на запись, накапливает полные 100 * 10 000 000 = 1 ГБ ОЗУ, прежде чем начать выгружать результат на стандартный вывод. Хотя вы не можете этого сказать по результатам моей тестовой программы, почти все 1,7 секунды, необходимые для форматирования и вывода результата, тратятся на форматирование, а не на вывод. (Если вы не перенаправляете на /dev/null, перед тем, как что-либо начнет выводиться на стандартный вывод, произойдет долгая пауза.) Это нехорошее поведение, если вы пытаетесь создать инструменты конвейерной обработки.
Вопрос 1. Я вижу в документации некоторые ссылки на fmt::format_to(). Можно ли это каким-то образом использовать для начала потоковой передачи и удаления результата до завершения форматирования и, таким образом, избежать компоновки полного результата в ядре?
Q2. Продолжая эту линию исследования, вместо передачи контейнера, есть ли способ передать, скажем, два итератора (которые, возможно, указывают на начало и конец очень большого файла) и прокачать эти данные через {fmt} для обработки? (и тем самым избежать необходимости сначала считывать весь файл в память)?

Код: Выделить всё

#include 
#include 
#include "fmt/format.h"
#include "fmt/ranges.h"
#include "time.h"

using namespace std;

inline long long
clock_monotonic_raw() {
struct timespec ct;
clock_gettime(CLOCK_MONOTONIC_RAW, &ct);
return ct.tv_sec * 1000000000LL + ct.tv_nsec;
}

inline double
dt() {
static long long t0 = 0;
if (t0 == 0) {
t0 = clock_monotonic_raw();
return 0.0;
}
long long t1 = clock_monotonic_raw();
return (t1 - t0) / 1.0e9;
}

int main(int argc, char** argv) {
fprintf(stderr, "%10.6f: ENTRY\n", dt());
vector v;
for (int i = 0; i < 10'000'000; ++i)
v.push_back('A' + i % 26);
string pad(98, ' ');
fprintf(stderr, "%10.6f: INIT\n", dt());
fmt::print(pad + "{}\n", fmt::join(v, "\n" + pad));
fprintf(stderr, "%10.6f: DONE\n", dt());
return 0;
}

matt@dworkin:fmt_test$ g++ -o mem_fmt -O3 -I ../fmt/include/ mem_fmt.cpp ../fmt/libfmt.a
matt@dworkin:fmt_test$ ./mem_fmt > /dev/null
0.000000: ENTRY
0.034582: INIT
1.769687: DONE
[из другого окна во время работы]

Код: Выделить всё

matt@dworkin:fmt_test$ ps -aux | egrep 'COMMAND|mem_fmt' | grep -v grep
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
matt       30292  2.8  6.2 1097864 999208 pts/0  S+   17:40   0:01 ./mem_fmt
Примечание VSZ размером 1,097864 ГБ

Подробнее здесь: https://stackoverflow.com/questions/784 ... large-data
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C++»