LINUX.ORG.RU

Самый быстрый способ объединить несколько больших файлов в один

 


0

1

Я сделал в коде питона вызов shell вида

cat "a" "b" > "c"

Может есть более быстрые способы. Гонять гигабайты через питон точно не быстрее

★★★★

Последнее исправление: post-factum (всего исправлений: 1)

чем cat не нравится? Если он в CPU не упирается, то навряд ли будет что-то быстрее. Разве что ещё с fallocate можно поиграться

mashina ★★★★★
()
Ответ на: комментарий от namezys

cow (copy on write) на уровне блоков ФС. auto значит что если механизм поддерживается фс, то будет задействован.

если файлы реально велики, то cat b>>c можно поменять на dd. Но надо эксперементально проверять.

MKuznetsov ★★★★★
()
Ответ на: комментарий от MKuznetsov

во. я буду знать куда копать. Если конечно на маке оно умеет. Это единственный скрипт, который работает под маком.

namezys ★★★★
() автор топика
Ответ на: комментарий от namezys

Можно через отображения файла в память.

Сделай вызов C из питона, который отобразит в память 3 файла(третий создать), потом через memcpy можно скопировать байтики из адресов, в которую отображен первый и второй файл в отображенную под третий файл память. Еще можно через write()/read() или fwrite()/fread() сделать.

SZT ★★★★★
()
Ответ на: комментарий от SZT

не думаю что это будет быстрее. Да и не стоит выигрыш возможных процентов такой сложности

namezys ★★★★
() автор топика
Ответ на: комментарий от namezys

такое, афаик, пока умеют только zfs и btrfs из позиксноподобных

mashina ★★★★★
()
Ответ на: комментарий от mashina

Я думаю, что splice уделает всех.

ага, уделает.

Есть обоснованные сомнения?

...where one of the descriptors must refer to a pipe

Ииии... что? Вот как известный тролль Линус Торвальдс рекомендует поступать:

#define _GNU_SOURCE
#include <fcntl.h>
#include <assert.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
        int fdin, fdout, pipefd[2];

        fdin = open(argv[1], O_RDONLY);
        fdout = open(argv[2], O_RDWR | O_CREAT, S_IRUSR);
        assert(pipe(pipefd) == 0);
        assert(fdin >= 0);
        assert(fdout >= 0);
        for (;;) {
                int nr = splice(fdin, NULL, pipefd[1], NULL, INT_MAX, 0);

                if (nr <= 0)
                        break;
                do {
                        int ret = splice(pipefd[0], NULL, fdout, NULL, nr, 0);
                        if (ret <= 0) {
                                perror("splice");
                                exit(1);
                        }
                        nr -= ret;
                } while (nr);
        }
}

Вопросы есть?

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

кстати, а sendfile не проще? %% In Linux kernels before 2.6.33, out_fd must refer to a socket. Since Linux 2.6.33 it can be any file. If it is a regular file, then sendfile() changes the file offset appropriately %%

anonymous
()
Ответ на: комментарий от anonymous

Наверняка проще, но я не знал, что sendfile так починили. Кроме того, у меня давняя нелюбовь к sendfile из-за его склонности вешать систему при ошибках.

Кстати, sendfile может оказаться переносимым решением, которое нужно ТС.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Спасибо, кэп.

Но если функция описана в posix +- я можно верить, что она реализована одинаково и хоть похожа по сигнатуре :) Есть к чему стремиться в общем ;)

https://developer.apple.com/library/mac/#documentation/Darwin/Reference/Manpa...

int
     sendfile(int fd, int s, off_t offset, off_t *len, struct sf_hdtr *hdtr, int flags);

[ENOTSOCK] The s argument does not refer stream oriented socket.

anonymous
()
Ответ на: комментарий от tailgunner

Ну ок, пусть будет так. Тем не менее, всё равно это не будет работать быстрее чем read() & write() для двух файлов по очевидным причинам.

mashina ★★★★★
()
Ответ на: комментарий от mashina

всё равно это не будет работать быстрее чем read() & write() для двух файлов по очевидным причинам.

Назови очевидные причины.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Оверхед от read()/write() через юзерспейсный буфер будет не сильно выше аналогичной операции от копирования через буфер пайпа, т.к. имеем почти такой же набор копирований.

Диски (hdd, ssd + их различные конфигурации) медленны, на фоне iowait'ов вообще трудно заметить разницу для единичного cat'а от подобных оптимизаций.

mashina ★★★★★
()
Ответ на: комментарий от mashina

Оверхед от read()/write() через юзерспейсный буфер будет не сильно выше аналогичной операции от копирования через буфер пайпа, т.к. имеем почти такой же набор копирований.

В случае splice копирования не будет.

на фоне iowait'ов

Борьба с iowait ровно такая же, как и в случае read/write - ftruncate заранее. Понятно, чтот задача всё равно I/O-bound, но splice что-то сэкономит за счет zero-copy и, возможно, за счет лучшего управления кэшем страниц.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

В случае splice копирования не будет.

Его может не быть если делать сплайс между пайпами(сокетами), будет меньше если между пайпом и файлом. Как бы дисковый кэш это не такой же буфер как и буфер пайпа.

и, возможно, за счет лучшего управления кэшем страниц

возможно, но заметить хоть как-то это можно будет только пока запись идёт в кэш.

mashina ★★★★★
()
Ответ на: комментарий от mashina

Как бы дисковый кэш это не такой же буфер как и буфер пайпа.

Я думаю, что splice реализован разумно и кэш зря не тратит.

возможно, но заметить хоть как-то это можно будет только пока запись идёт в кэш.

Если splice не разбазаривает кэш, то это скажется на производительности системы в целом.

tailgunner ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.