Saya memiliki direktori dengan lebih dari 400 GiB data di dalamnya. Aku ingin memeriksa bahwa semua file dapat dibaca tanpa kesalahan, sehingga cara sederhana saya pikir adalah untuk tar
menjadi /dev/null
. Tetapi sebaliknya saya melihat perilaku berikut:
$ time tar cf /dev/null .
real 0m4.387s
user 0m3.462s
sys 0m0.185s
$ time tar cf - . > /dev/null
real 0m3.130s
user 0m3.091s
sys 0m0.035s
$ time tar cf - . | cat > /dev/null
^C
real 10m32.985s
user 0m1.942s
sys 0m33.764s
Perintah ketiga di atas secara paksa dihentikan oleh Ctrl+ Csetelah berjalan cukup lama. Selain itu, sementara dua perintah pertama bekerja, indikator aktivitas perangkat penyimpanan yang berisi .
hampir selalu tidak digunakan. Dengan perintah ketiga indikator terus menyala, yang berarti kesibukan ekstrem.
Jadi sepertinya, ketika tar
dapat mengetahui bahwa file outputnya /dev/null
, yaitu ketika /dev/null
dibuka secara langsung untuk memiliki file handle yang tar
ditulis, file body muncul dilewati. (Menambahkan v
opsi untuk tar
tidak mencetak semua file dalam direktori menjadi tar
'merah.)
Jadi saya bertanya-tanya, mengapa demikian? Apakah ini semacam optimasi? Jika ya, lalu mengapa tar
bahkan ingin melakukan optimasi yang meragukan untuk kasus khusus seperti itu?
Saya menggunakan GNU tar 1.26 dengan glibc 2.27 di Linux 4.14.105 amd64.
find . -type f -exec shasum -a256 -b '{}' +
. Tidak hanya itu benar - benar membaca dan memeriksa semua data, tetapi jika Anda menyimpan hasilnya, Anda dapat menjalankannya lagi nanti untuk memeriksa bahwa konten file tidak berubah.pv
:tar -cf - | pv >/dev/null
. Itu menghindari masalah dan memberi Anda informasi kemajuan (berbagaipv
opsi)gtar -cf /dev/zero ...
untuk mendapatkan apa yang Anda suka.Jawaban:
Ini adalah optimasi terdokumentasi :
sumber
info tar
...info
atau sebagai HTML di browser.Ini dapat terjadi dengan berbagai program, misalnya, saya memiliki perilaku itu sekali ketika hanya menggunakan
cp file /dev/null
; alih-alih mendapatkan perkiraan kecepatan baca disk saya, perintah kembali setelah beberapa milidetik.Sejauh yang saya ingat, itu ada di Solaris atau AIX, tetapi prinsipnya berlaku untuk semua jenis sistem unix-y.
Di masa lalu, ketika sebuah program menyalin file ke suatu tempat, itu akan bergantian antara
read
panggilan yang mendapatkan beberapa data dari disk (atau apa pun yang deskriptor file merujuk) ke memori (dengan jaminan semuanya ada di sana ketikaread
kembali) danwrite
panggilan (Yang mengambil sebagian memori dan mengirim konten ke tujuan).Namun, setidaknya ada dua cara baru untuk mencapai hal yang sama:
Linux memiliki panggilan sistem
copy_file_range
(tidak portabel ke unix lain sama sekali) dansendfile
(agak portabel; awalnya dimaksudkan untuk mengirim file ke jaringan, tetapi dapat menggunakan tujuan apa pun sekarang). Mereka dimaksudkan untuk mengoptimalkan transfer; jika program menggunakan salah satu dari itu, mudah dibayangkan bahwa kernel mengenali targetnya/dev/null
dan mengubah panggilan sistem menjadi no-opProgram dapat digunakan
mmap
untuk mendapatkan isi file alih-alihread
, ini pada dasarnya berarti "pastikan data ada ketika saya mencoba mengakses potongan memori" daripada "pastikan data ada di sana ketika panggilan sistem kembali". Jadi suatu program dapatmmap
sumber file, kemudian memanggilwrite
potongan memori yang dipetakan. Namun, karena tulisan/dev/null
tidak perlu mengakses data tertulis, kondisi "pastikan itu ada" tidak pernah dipicu, mengakibatkan file tidak dibaca juga.Tidak yakin apakah gnu tar menggunakan, dan yang mana, dari dua mekanisme ini ketika mendeteksi itu sedang menulis
/dev/null
, tetapi mereka adalah alasan mengapa setiap program, ketika digunakan untuk memeriksa kecepatan baca , harus dijalankan dengan| cat > /dev/null
alih - alih> /dev/null
- dan mengapa| cat > /dev/null
harus harus dihindari dalam semua kasus lain.sumber
tar
halaman info GNU (lihat jawaban lain) adalah ia memiliki mode khusus untuk ini, yang mungkin hanya file statistik tanpa membukanya. Sebenarnya saya baru saja memeriksatar cf /dev/null foo*
pada beberapa file dan ya, hanyanewfstatat(..., AT_SYMLINK_NOFOLLOW)
panggilan sistem, bahkanopen()
yang mungkin memperbarui atime. Tetapi +1 untuk menjelaskan mekanisme di mana ini bisa terjadi tanpa harus mendeteksinya secara khusus.splice(2)
di Linux. Sebenarnya, mengganti,cat > /dev/null
denganpv -q > /dev/null
(yang menggunakansplice()
Linux) kemungkinan akan mengurangi overhead. Ataudd bs=65536 skip=9999999999 2> /dev/null
, atauwc -c > /dev/null
atautail -c1 > /dev/null
...