GNU/Linux >> Znalost Linux >  >> Linux

Nejúčinnější způsob kopírování souboru v Linuxu

Pokud víte, že budou používat linux> 2.6.17, splice() je způsob, jak provést nulové kopírování v linuxu:

 //using some default parameters for clarity below. Don't do this in production.
 #define splice(a, b, c) splice(a, 0, b, 0, c, 0)
 int p[2];
 pipe(p);
 int out = open(OUTFILE, O_WRONLY);
 int in = open(INFILE, O_RDONLY)
 while(splice(p[0], out, splice(in, p[1], 4096))>0);

Bohužel nemůžete použít sendfile() zde, protože cíl není zásuvka. (Název sendfile() pochází z send() + "soubor").

Pro nulovou kopii můžete použít splice() jak navrhuje @Dave. (Kromě toho, že to nebude nulová kopie; bude to „jedna kopie“ z mezipaměti stránek zdrojového souboru do mezipaměti stránek cílového souboru.)

Nicméně... (a) splice() je specifický pro Linux; a (b) téměř jistě můžete stejně dobře používat přenosná rozhraní, pokud je používáte správně.

Stručně řečeno, použijte open() + read() + write() s malým dočasný buffer. Doporučuji 8K. Váš kód by tedy vypadal nějak takto:

int in_fd = open("source", O_RDONLY);
assert(in_fd >= 0);
int out_fd = open("dest", O_WRONLY);
assert(out_fd >= 0);
char buf[8192];

while (1) {
    ssize_t read_result = read(in_fd, &buf[0], sizeof(buf));
    if (!read_result) break;
    assert(read_result > 0);
    ssize_t write_result = write(out_fd, &buf[0], read_result);
    assert(write_result == read_result);
}

Pomocí této smyčky budete kopírovat 8 kB z mezipaměti stránek in_fd do mezipaměti CPU L1 a poté je zapsat z mezipaměti L1 do mezipaměti stránek out_fd. Poté přepíšete tuto část mezipaměti L1 dalším 8K blokem ze souboru a tak dále. Čistým výsledkem je, že data v buf ve skutečnosti se nikdy neuloží do hlavní paměti (s výjimkou možná jednou na konci); z hlediska systémové RAM je to stejně dobré jako použití "nulové kopie" splice() . Navíc je dokonale přenosný na jakýkoli systém POSIX.

Všimněte si, že malá vyrovnávací paměť je zde klíčová. Typické moderní CPU mají 32K nebo tak pro datovou mezipaměť L1, takže pokud uděláte vyrovnávací paměť příliš velkou, bude tento přístup pomalejší. Možná mnohem, mnohem pomaleji. Udržujte tedy vyrovnávací paměť v rozsahu „několik kilobajtů“.

Samozřejmě, pokud váš diskový subsystém není velmi rychlý, šířka pásma paměti pravděpodobně není vaším omezujícím faktorem. Takže bych doporučil posix_fadvise aby jádro vědělo, co chystáte:

posix_fadvise(in_fd, 0, 0, POSIX_FADV_SEQUENTIAL);

To dá linuxovému jádru náznak, že jeho mašinérie pro čtení napřed by měla být velmi agresivní.

Také bych doporučil použít posix_fallocate k předběžnému přidělení úložiště pro cílový soubor. To vám předem řekne, zda vám dojde disk. A pro moderní jádro s moderním souborovým systémem (jako XFS) to pomůže snížit fragmentaci v cílovém souboru.

Poslední věc, kterou bych doporučil, je mmap . Je to obvykle nejpomalejší přístup ze všech díky TLB thrashingu. (Nejnovější jádra s "transparentními obrovskými stránkami" by to mohla zmírnit; nedávno jsem to nezkoušel. Ale určitě to bývalo velmi špatné. Takže bych se obtěžoval pouze testováním mmap pokud máte spoustu času na benchmark a velmi nedávné jádro.)

[Aktualizovat]

V komentářích je nějaká otázka, zda splice z jednoho souboru do druhého je nulová kopie. Vývojáři linuxového jádra tomu říkají „kradení stránek“. Obě manuálové stránky pro splice a komentáře ve zdrojovém kódu jádra říkají, že SPLICE_F_MOVE flag by měl tuto funkci poskytovat.

Bohužel podpora pro SPLICE_F_MOVE byl vytržen v 2.6.21 (v roce 2007) a nikdy nebyl nahrazen. (Komentáře ve zdrojích jádra nebyly nikdy aktualizovány.) Pokud prohledáte zdroje jádra, najdete SPLICE_F_MOVE není ve skutečnosti nikde odkazováno. Poslední zpráva, kterou jsem našel (z roku 2008), říká, že „čeká na náhradu“.

Pointa je, že splice z jednoho souboru do druhého volá memcpy přesunout data; není nulová kopie. To není o moc lepší, než můžete udělat v uživatelském prostoru pomocí read /write s malými vyrovnávací paměti, takže byste se mohli držet standardních přenosných rozhraní.

Pokud se někdy do linuxového jádra přidá „krádež stránek“, pak výhody splice by bylo mnohem větší. (A i dnes, když je cílem soket, získáte skutečnou nulovou kopii, takže splice atraktivnější.) Ale pro účely této otázky splice vás moc nekoupí.


Linux
  1. Nejúčinnější způsob, jak vyprázdnit obsah souboru?

  2. Nainstalujte AzCopy na Linux – nejrychlejší způsob kopírování v Azure

  3. zkopírujte soubor z Windows do Linuxu

  1. Zkopírujte soubory v terminálu Linux

  2. Snadný způsob, jak skrýt soubory a adresáře v Linuxu

  3. Získejte nejnovější soubor v adresáři v systému Linux

  1. nejrychlejší způsob převodu souboru odděleného tabulátory na csv v linuxu

  2. Zkopírujte obsah souboru do schránky v terminálu Linux

  3. pscp zkopírujte soubor vzdáleně z Windows do Linuxu