Используйте sendfile() для копирования файла с помощью потоков или другого эффективного метода копирования файла.

StackOverflow https://stackoverflow.com//questions/25031044

Вопрос

Я пытаюсь использовать системный вызов Linux sendfile() скопировать файл с помощью потоков.

Меня интересует оптимизация этих частей кода:

fseek(fin, size * (number) / MAX_THREADS, SEEK_SET);  
fseek(fout, size * (number) / MAX_THREADS, SEEK_SET); 
/* ... */
fwrite(buff, 1, len, fout);  

Код:

void* FileOperate::FileCpThread::threadCp(void *param)
{
    Info *ft = (Info *)param;
    FILE *fin = fopen(ft->fromfile, "r+");
    FILE *fout = fopen(ft->tofile, "w+");

    int size = getFileSize(ft->fromfile);

    int number =  ft->num;
    fseek(fin, size * (number) / MAX_THREADS, SEEK_SET);
    fseek(fout, size * (number) / MAX_THREADS, SEEK_SET);

    char buff[1024] = {'\0'};
    int len = 0;
    int total = 0;

    while((len = fread(buff, 1, sizeof(buff), fin)) > 0)
    {
        fwrite(buff, 1, len, fout);
        total += len;

        if(total > size/MAX_THREADS)
        {
            break;
        }
    }

    fclose(fin);
    fclose(fout);
}
Это было полезно?

Решение

Копирование файлов не привязано к процессору;если бы это было так, вы, вероятно, обнаружите, что ограничение находится на уровне ядра, и вы ничего не можете сделать на уровне пользователя, чтобы распараллелить его.

Такие «улучшения», сделанные на механических приводах, на самом деле будут деградировать пропускная способность.Вы тратите время на поиск файла вместо того, чтобы читать и записывать его.

Если файл длинный и вы не ожидаете, что данные для чтения или записи понадобятся в ближайшее время, может возникнуть соблазн использовать O_DIRECT флаг открыт.Это плохая идея, поскольку O_DIRECT API по сути сломан по дизайну.

Вместо этого вы должны использовать posix_fadvise как в исходном, так и в целевом файле с флагами POSIX_FADV_SEQUENTIAL и POSIX_FADV_NOREUSE.После завершения вызова write (или sendfile) нужно сообщить, что данные больше не нужны — передать POSIX_FADV_DONTNEED.Таким образом, кэш страниц будет использоваться только в той степени, в которой это необходимо для поддержания потока данных, и страницы будут перезагружены, как только данные будут израсходованы (записаны на диск).

А sendfile не будет переносить данные файла в пространство пользователя, поэтому это еще больше снижает нагрузку на память и кэш процессора.Это единственное разумное улучшение, которое вы можете сделать для копирования файлов, не зависящих от устройства.

Также желательно выбрать разумный размер фрагмента.Учитывая, что современные накопители обеспечивают скорость более 100 Мбайт/с, вы можете захотеть передать по мегабайту за раз, и всегда кратно размеру страницы в 4096 байт - таким образом (4096*256) это достойный начальный размер фрагмента, который можно обработать за один раз. sendfile или read/write звонки.

Распараллеливание чтения, как вы его предлагаете, имеет смысл только на томах RAID 0 и только тогда, когда входные и выходные файлы располагаются на физических дисках.Затем вы можете иметь один поток на меньшее из числа физических дисков исходного и целевого томов, охватываемых файлом.Это необходимо только в том случае, если вы не используете асинхронный файловый ввод-вывод.При асинхронном вводе-выводе вам в любом случае не понадобится более одного потока, особенно если размеры фрагментов велики (мегабайт+), а штраф за задержку в одном потоке незначителен.

Нет смысла распараллеливать одну копию файла на SSD, если только вы действительно не находитесь в какой-то очень странной системе.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top