GNU/Linux >> Belajar Linux >  >> Linux

Cara paling efisien untuk menyalin file di Linux

Jika Anda tahu mereka akan menggunakan linux> 2.6.17, splice() adalah cara untuk melakukan zero-copy di linux:

 //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);

Sayangnya, Anda tidak dapat menggunakan sendfile() di sini karena tujuannya bukan soket. (Nama sendfile() berasal dari send() + "berkas").

Untuk zero-copy, Anda dapat menggunakan splice() seperti yang disarankan oleh @Dave. (Kecuali itu tidak akan menjadi salinan nol; itu akan menjadi "satu salinan" dari cache halaman file sumber ke cache halaman file tujuan.)

Namun... (a) splice() khusus untuk Linux; dan (b) Anda hampir pasti dapat melakukannya dengan baik menggunakan antarmuka portabel, asalkan Anda menggunakannya dengan benar.

Singkatnya, gunakan open() + read() + write() dengan kecil penyangga sementara. Saya sarankan 8K. Jadi kode Anda akan terlihat seperti ini:

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);
}

Dengan loop ini, Anda akan menyalin 8K dari cache halaman in_fd ke cache CPU L1, lalu menuliskannya dari cache L1 ke cache halaman out_fd. Kemudian Anda akan menimpa bagian cache L1 itu dengan potongan 8K berikutnya dari file tersebut, dan seterusnya. Hasil akhirnya adalah data dalam buf tidak akan pernah benar-benar disimpan di memori utama sama sekali (kecuali mungkin sekali di akhir); dari sudut pandang RAM sistem, ini sama bagusnya dengan menggunakan "zero-copy" splice() . Plus itu sangat portabel untuk sistem POSIX apa pun.

Perhatikan bahwa buffer kecil adalah kuncinya di sini. CPU modern tipikal memiliki 32K atau lebih untuk cache data L1, jadi jika Anda membuat buffer terlalu besar, pendekatan ini akan lebih lambat. Mungkin jauh, jauh lebih lambat. Jadi pertahankan buffer dalam kisaran "beberapa kilobyte".

Tentu saja, kecuali subsistem disk Anda sangat cepat, bandwidth memori mungkin bukan faktor pembatas Anda. Jadi saya akan merekomendasikan posix_fadvise agar kernel mengetahui apa yang Anda lakukan:

posix_fadvise(in_fd, 0, 0, POSIX_FADV_SEQUENTIAL);

Ini akan memberi petunjuk kepada kernel Linux bahwa mesin baca-depannya harus sangat agresif.

Saya juga menyarankan menggunakan posix_fallocate untuk melakukan praalokasi penyimpanan untuk file tujuan. Ini akan memberi tahu Anda sebelumnya apakah Anda akan kehabisan disk. Dan untuk kernel modern dengan sistem file modern (seperti XFS), ini akan membantu mengurangi fragmentasi pada file tujuan.

Hal terakhir yang saya rekomendasikan adalah mmap . Ini biasanya merupakan pendekatan paling lambat dari semuanya berkat meronta-ronta TLB. (Kernel yang sangat baru dengan "hugpages transparan" mungkin mengurangi ini; saya belum mencoba baru-baru ini. Tapi itu pasti sangat buruk. Jadi saya hanya akan repot-repot menguji mmap jika Anda punya banyak waktu untuk membandingkan dan kernel yang sangat baru.)

[Perbarui]

Ada beberapa pertanyaan di komentar tentang apakah splice dari satu file ke file lainnya adalah zero-copy. Pengembang kernel Linux menyebutnya "pencurian halaman". Kedua halaman manual untuk splice dan komentar di sumber kernel mengatakan bahwa SPLICE_F_MOVE bendera harus menyediakan fungsi ini.

Sayangnya, dukungan untuk SPLICE_F_MOVE dicabut pada 2.6.21 (pada tahun 2007) dan tidak pernah diganti. (Komentar di sumber kernel tidak pernah diperbarui.) Jika Anda mencari di sumber kernel, Anda akan menemukan SPLICE_F_MOVE sebenarnya tidak dirujuk di mana pun. Pesan terakhir yang dapat saya temukan (dari 2008) mengatakan "menunggu pengganti".

Intinya adalah splice itu dari satu file ke file lain memanggil memcpy untuk memindahkan data; itu tidak salinan nol. Ini tidak jauh lebih baik daripada yang dapat Anda lakukan di ruang pengguna menggunakan read /write dengan buffer kecil, jadi sebaiknya Anda tetap menggunakan antarmuka portabel standar.

Jika "pencurian halaman" pernah ditambahkan kembali ke kernel Linux, maka keuntungan dari splice akan jauh lebih besar. (Dan bahkan hari ini, ketika tujuannya adalah soket, Anda mendapatkan salinan nol yang sebenarnya, membuat splice lebih menarik.) Tapi untuk tujuan pertanyaan ini, splice tidak banyak membelikanmu.


Linux
  1. Salin file di terminal Linux

  2. Instal AzCopy di Linux – Cara tercepat untuk menyalin di Azure

  3. cara tercepat mengonversi file yang dibatasi tab ke csv di linux

  1. Salin konten file ke clipboard di terminal Linux

  2. salin file pscp dari jarak jauh dari Windows ke Linux

  3. menyalin file dari windows ke Linux

  1. Cara Mudah Menyembunyikan File dan Direktori di Linux

  2. gcp – Utilitas Mesin Fotokopi File Tingkat Lanjut Untuk Linux

  3. Metode Paling Efisien Untuk Mengosongkan Isi File?