У меня 1000000 файлов 4-20 кб в каталоге. Мне нужно скопировать этот каталог. Но, похоже, мне нужно искать каждый файл, так что это занимает довольно много времени.
Есть ли способ, которым я могу ускорить это?
В настоящее время я думаю, что, если бы я мог получить блоки дисков, которые занимают эти файлы, я мог бы отсортировать их, объединить блоки, которые были близки (учитывая, что последовательное чтение часто быстрее, чем поиск) и прочитать эти блоки, чтобы они были в оперативной памяти кеш (у меня 32 гб оперативки) перед выполнением копирования.
Но чтобы это работало, мне нужен способ определить, на каких блоках находятся файлы.
Я использую EXT4 на магнитном устройстве (т.е. не SSD).
Редактировать:
Это должно работать, но это не так:
ls |
parallel -IOO --pipe "sudo parallel -j100 hdparm --fibmap {}'|tail -n +5'" |
sort -nk 2 |
perl -ane 'if($u+10000 < $F[1]) { print "$l ",($u-$l),"\n"; $l=$F[1] } $u=$F[2]' |
sudo parallel --colsep ' ' dd if=/dev/sda1 skip={1} bs=512 count={2} '| cat >/dev/null'
При тестировании большого файла он не кэширует файл.
Edit2:
Вот несколько ориентиров. Кэш сбрасывался ( echo 3 >/proc/sys/vm/drop_caches
) между каждым запуском. Измерения сделаны с iostats -dkx 5
.
rsync -Hav foo/ bar/: 1800 KB/s
cp -a foo/ bar/: 3600 KB/s
cat sort-by-inode | parallel -j1 -X cp foo/{} bar/: 5000 KB/s
cat sort-by-inode | shuf | parallel -j1 -X cp foo/{} bar/: 3000 KB/s
cat sort-by-inode | shuf | parallel -j10 -X cp foo/{} bar/: 7000 KB/s
cat sort-by-inode | parallel -j10 -X cp foo/{} bar/: 8000 KB/s
cat sort-by-inode | parallel -j100 -X cp foo/{} bar/: 9000 KB/s
cat sort-by-inode | parallel -j500 -X cp foo/{} bar/: 10000 KB/s
Так что мы можем извлечь из этого?
Кажется, сортировка по индоду - хорошая идея. Но кажется, что распараллеливание нескольких cp
увеличивает производительность еще дальше. Стоит подчеркнуть, что источником foo/
является магнитный диск, поэтому нападает на миф о том, что распараллеливание ввода-вывода с одним шпинделем не ускорит ввод-вывод: распараллеливание четко и последовательно ускоряет копирование здесь.
источник
cp -r /mnt/dir1 /mnt/dirdest
или что-то вродеcp /mnt/dir1/* /mnt/dirdest
?Ответы:
При условии, что
readdir
не сортируются по номеру инодаВы можете попытаться ускорить копирование путем копирования файлов в порядке следования узлов.
Это значит использовать что-то вроде этого:
источник
ls -U
недостаточно, потому что не сортирует по номерам инодов ... а зачем мне хотеть-1
?-1
просто перечисляет «один файл на строку» - это не помогает с новыми строками в именах файлов. Для этого вы можете использоватьfind -print0/xargs -O
.mkdir tmp; cd tmp; touch foo"<RETURN>"bar; ls
печатает 'foo? Bar'. Аls -1
также печатает «foo? Bar». Аls -1 | wc -l
печатает «2». Afind -ls
печатает имя файла как «./foo\nbar».cp -i
Ls -1` x` терпит неудачу с "ф: мишень„х“не является каталогом.-q
делает то, что я думал,-1
будет! Опять же, мои извинения - не говоря уже о спасибо.GNU
tar
- поpax
традиции - обрабатывает жесткие ссылки самостоятельно.Таким образом, у вас есть только два
tar
процесса, и вам не нужноcp
повторять вызовы снова и снова.источник
Аналогично ответу @ maxschlepzig , вы можете анализировать выходные данные
filefrag
для сортировки файлов в порядке появления их первых фрагментов на диске:MMV с приведенным выше
sed
сценарием, поэтому обязательно тщательно протестируйте.В противном случае, что бы вы ни делали,
filefrag
(частьe2fsprogs
) будет гораздо быстрее использовать, чем,hdparm
поскольку он может принимать несколько файловых аргументов. Только накладные расходы на запускhdparm
1000000 раз добавят много накладных расходов.Также, вероятно, было бы не так сложно написать
perl
скрипт (или программу на C)FIEMAP
ioctl
для каждого файла, создать отсортированный массив блоков, которые должны быть скопированы, и файлы, к которым они принадлежат, и затем скопировать все по порядку: Чтение размера каждого блока из соответствующего файла (будьте осторожны, чтобы не исчерпать дескрипторы файлов).источник
tar
для их файлов.qtar
с открытым исходным кодом; сейчас на github.com/chlunde/qtar