Задать вопрос
@chaturanga

Как ускорить чтение строк из файла?

Имеется файл, часть которого содержит строки определенного формата:
3 символа, пробел, 3 символа, пробел, число, например

AAA BBB 1111
AAA CCC 22222
BBB CCC 333333

и т.д.
Строк 40KK +
Их количество заранее известно.
Считываю их сейчас так:
for (int i = 0; i < k; i++)
{
	fgets(str, 32, FILE_IN);
	sscanf(str, "%s %s %d\n", src, dst, &cost);
}

Чтение занимает порядка 5 сек.
Вариант с
fscanf(FILE_IN, "%s %s %d\n", src, dst, &cost);
Занимает больше 8 сек.
Как можно ускорить чтение/разбор строк?
  • Вопрос задан
  • 192 просмотра
Подписаться 2 Простой Комментировать
Решения вопроса 1
wataru
@wataru
Разработчик на С++, экс-олимпиадник.
Может, ручной разбор будет быстрее. Читайте весь файл в большой буфер. Трехсимвольные строки - это пусть будут тупо char* на начало строк в этом буфере. Там пробелы замените на '\0' только. Вот вы уже сэкономили на разборе строк и выделении под них памяти. Числа руками разобрать придется правда (умножение на 10 + следующий символ - '0').

Еще, вместо чтения файла какой-нибудь mmap может быть быстрее.

Потом это можно еще и распараллелить каким-нибудь OpenMP, например. Разбейте буфер на примерно равные части, чуть подвигайте границы, чтоб они на переводы строк приходились и каждый кусок разбирайте отдельно.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
egor_nullptr
@egor_nullptr Куратор тега C
mmap + ручной разбор, получилось примерно в 10 раз быстрее, чем fgets + sscanf
Код

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>

int main(int argc, char** argv)
{
    int fin = open(argv[1], O_RDONLY);
    struct stat finfo = {0};
    fstat(fin, &finfo);
    char *map = mmap(0, finfo.st_size, PROT_READ, MAP_SHARED, fin, 0);

    char src[4] = {0};
    char dst[4] = {0};
    int cost;
    int i;
    int off = 0;

    while (off < finfo.st_size)
    {   
        memcpy(src, map + off, 3); 
        memcpy(dst, map + off + 4, 3);
        i = 0; 
        cost = 0;
        while (map[off + 8 + i] != 10) { 
            cost = cost * 10 + map[off + 8 + i] - 48;
            ++i;
        };
        off += 9 + i;
    };

    munmap(map, finfo.st_size);
    close(fin);

    return EXIT_SUCCESS;
}

Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы