Накопление невыполненной работы на std :: cin приводит к потере данных - PullRequest
0 голосов
/ 12 апреля 2020

У меня есть внешний двоичный файл, который создает бесконечный поток двоичных данных (~ 10 МБ / с) на стандартный вывод, и я пытаюсь написать программу на C ++ для его использования. Моя потребительская программа имеет несколько необычный паттерн: сначала она читает небольшое количество данных из потока (~ 32 КБ), обрабатывает их примерно одну минуту, а затем начинает снова потреблять данные с гораздо более высокой скоростью (> 50 МБ / с) .

Я вызываю программу следующим образом: $ my_producer | my_consumer.

Поскольку потребитель изначально намного медленнее, чем потребитель, я ожидаю, что канал создаст отставание около 60s * 10 MiB/s = 600 MiB. Однако после начальной задержки в одну минуту мой потребитель начинает потреблять данные со скоростью всего ~ 10 МБ / с, подразумевая, что данные, полученные в течение этого одноминутного интервала, были потеряны; почему?

Соответствующий код для потребителя выглядит примерно так:

std::vector<char> StreamSource::Read(std::size_t size) {
  auto data = std::vector<char>(size);
  stream_.read(data.data(), size);
  data.resize(stream_.gcount());
  assert(stream_.good() || stream_.eof());
  return data;
}

std::istream& stream_;  // Initialized to std::cin

Интересно, что запись в файл и затем передача этого файла потребителю работает, как и ожидалось!

$ my_producer > ~/Desktop/data
$ cat ~/Desktop/data | my_consumer

Я провел кучу тестов, чтобы убедиться, что мой продюсер вряд ли виноват; следующее не удается, потому что производитель обнаруживает «короткую запись»:

$ my_producer | throttle -M1 > ~/Desktop/data

Я ищу совет о том, как объяснить отсутствующие данные. Если это актуально, я работаю на MacOS.

Спасибо!

1 Ответ

0 голосов
/ 12 апреля 2020

Я почти уверен, что ни одна ОС не позволяет каналу наращивать до 600 МБ, конец записи блокируется, когда канал заполнен. Если вы хотите, чтобы накапливался такой большой объем данных, в вашем приложении должен быть поток, который непрерывно читает из cin и буферизует данные, тогда ваше приложение может читать из этого буфера, а не cin.

Согласно https://unix.stackexchange.com/questions/11946/how-big-is-the-pipe-buffer длина трубы обычно не превышает 64 КБ.

...