Быстрый и простой способ чтения из стандартного ввода по одному байту за раз в C ++ - PullRequest
0 голосов
/ 10 июня 2019

Следующий наивный код для чтения из stdin и подсчета количества вхождений каждого байта очень медленный и занимает около 1m40 для обработки 1 ГБ данных на моем компьютере.

int counts[256] {0};

uint8_t byte;
while (std::cin >> std::noskipws >> byte) {
  ++counts[byte];
}

Выполнение буферизованного чтения, конечно, намного быстрее, обработка 1 ГБ менее чем за секунду.

uint8_t buf[4096];

uint8_t byte;
int n;
while (n = read(0, (void *)buf, 4096), n > 0) {
  for (int i = 0; i < n; ++i) {
    ++counts[buf[i]];
  }
}

Однако его недостатком является то, что он более сложный и требует ручного управления буфером.

Есть ли какой-нибудь способ считывания побайтного потока в стандарте C ++, такой же простой, очевидный и идиоматичный, как первый фрагмент, но такой же производительный, как и второй?

Ответы [ 2 ]

3 голосов
/ 11 июня 2019

Это кажется интересной проблемой. Мои результаты здесь:

without cin sync      : 34.178s
with cin sync         : 14.347s
with getchar          : 03.911s
with getchar_unlocked : 00.700s

Исходный файл был сгенерирован с использованием:

$ dd if=/dev/urandom of=file.txt count=1024 bs=1048576

Первый мой справочник, без изменений: 34.178s

#include <bits/stdc++.h>
int main(int argc, char **argv) {
    FILE *f = freopen(argv[1], "rb", stdin);
    int counts[256] {0};

    uint8_t byte;
    while (std::cin >> std::noskipws >> byte) {
      ++counts[byte];
    }
    return 0;
}

Использование std::ios::sync_with_stdio(false);: 14.347s

#include <bits/stdc++.h>
int main(int argc, char **argv) {
    std::ios::sync_with_stdio(false);
    FILE *f = freopen(argv[1], "rb", stdin);
    int counts[256] {0};

    uint8_t byte;
    while (std::cin >> std::noskipws >> byte) {
      ++counts[byte];
    }
    return 0;
}

С getchar: 3.911s

#include <bits/stdc++.h>
int main(int argc, char **argv) {
    FILE *f = freopen(argv[1], "rb", stdin);
    int v[256] {0};
    unsigned int b;
    while ((b = getchar()) != EOF) {
        ++v[b];
    }
    return 0;
}

С getchar_unlocked: 0.700s

#include <bits/stdc++.h>
int main(int argc, char **argv) {
    FILE *f = freopen(argv[1], "rb", stdin);
    int v[256] {0};
    unsigned int b;
    while ((b = getchar_unlocked()) != EOF) {
        ++v[b];
    }
    return 0;
}

Конфигурация моей машины:

CPU  : Intel(R) Core(TM) i5-3210M CPU @ 2.50GHz
MEM  : 12GB
Build: g++ speed.cc -O3 -o speed
g++ v: g++ (Ubuntu 7.4.0-1ubuntu1~18.04) 7.4.0
exec : time ./speed file.txt

Для меня getchar_unlocked - это самый быстрый способ чтения байтов без сохранения буфера.

0 голосов
/ 10 июня 2019

Я бы попробовал это:

std::ios::sync_with_stdio(false);

Это ускорит cin на большую сумму.

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