Чому переміщення деяких файлів у папці займає більше часу, ніж переміщення всієї папки?


21

У мене є мільйони зображень на моєму хмарному сервері ubuntu. Коли я переміщу повну папку, що містить 12 мільйонів зображень за допомогою mvкоманди, це відбувається майже миттєво. Однак, коли я бачу mvлише зображення (не папку), то це потребує певного часу. Чи є спосіб перемістити всі зображення так само швидко, як папки?

Ось що відбувається:

  1. src папка має 12 мільйонів зображень, і я переміщу це в папку dst за допомогою

    $ mv  src ../dst
    

    Відбувається негайно

  2. Всередині папки src я роблю це для переміщення:

    find -maxdepth 1 -name '*.jpg' -exec mv -t ../../dst/ {} +
    

    Це займає певний час.

Чи є спосіб пришвидшити другий процес?


1
Не рішення - але для уточнення: cmd2 повинен бути повільнішим, ніж cmd1, як він використовує find, а потім виконує переміщення для результату. Це ніколи не може бути таким швидким, як прямий рух без попереднього пошуку.
dufte

ймовірно, dstзнаходиться в розділі, тоді як ../../dstзнаходиться на іншому.
phuclv

Як написано, це навіть не схоже на дійсне виклик знаходження. Не вистачає жодного {}аргументу, де ім'я файлів було б розширено.
R ..

Я подав редагування, яке змінює заголовок, видаляючи посилання на "образи" і замінюючи його нубом справи - це переміщення окремих файлів проти переміщення всієї папки. Я сподіваюся, що це прийнято хтось із представником, щоб це зробити.
Monty Harder

1
Це неправдиве виклик find. find ... -exec mv -t ../../dst/ {} \;дзвонить mvодин раз у файл; find ... -exec mv -t ../../dest {} +було б набагато швидше, копіюючи якомога більше файлів за виклик, але все ж не так швидко, як переміщення самого каталогу, як пояснено dadexix86 .
чепнер

Відповіді:


50

TL; DR : Ні

Для меншої кількості файлів вам не знадобиться, findале навіть у цьому спрощеному та меншому випадку, якщо ви просто

mv *.jpg ../../dst/

це займе більше часу, ніж переміщення всього каталогу відразу.


Чому? Сенс у тому, щоб зрозуміти, що mvробить.

Коротко кажучи, mvпереміщує число (яке ідентифікує каталог або файл) з inode (каталог, що містить його), на інший, і ці індекси оновлюються в журналі файлової системи або в FAT (якщо файлова система реалізується таким чином).

Якщо джерело та призначення знаходяться в одній файловій системі, фактичного руху даних немає, воно просто змінює положення, точку, до якої вони прикріплені.

Отже, коли ви маєте mv один каталог, ви робите цю операцію один раз .

Але коли ви переміщаєте 1 мільйон файлів, ви робите цю операцію в 1 мільйон разів .

Щоб навести практичний приклад, у вас є дерево з багатьма гілками. Зокрема, є один вузол, до якого прикріплено 1 мільйон гілок.
Щоб вирізати ці гілки і перемістити їх кудись інше, ви можете або вирізати кожну з них, так що ви зробите 1 мільйон надрізів, або виріжте безпосередньо перед вузлом, зробивши таким чином лише один зріз (це різниця між переміщенням файлів і каталог).


4
Вам слід включити, що а mvв тій же файловій системі є лише переписати запис TOC.
Videonauth

Я не впевнений, що я розумію, що ви маєте на увазі під TOC. Наскільки я знаю, у файлових системах ext немає, або NTFS, або btrfs тощо. FAT має таблицю (з якої вона бере назву), але, наприклад, ext зберігає імена та блоки, а також батьки, діти та іншу інформацію у індексах. Якщо ви можете вказати мені на якусь посилання, де пояснено, де у ext FS є свій TOC і для чого він використовується, я з радістю прочитаю та
оновлю

10
Гм. mv *.jpgшвидше за все, не вдасться отримати 12 мільйонів файлів, тому він використовує find. Я вважаю, що більшість Unixes, Linux, які я вважаю (якщо хтось не змінив їх протягом останніх 5-10 років), мають обмежену максимальну довжину командного рядка. Я думаю, що це було 64K для Linux давно. Це ж обмеження стосується змінних середовища, я впевнений.
Zan Lynx

1
Переміщення файлу більше стосується переміщення його імені . Записи каталогів у Unix містять ім'я файлу та номер inode, які в основному є вказівником на решту метаданих. Каталог - це лише особливий вид файлу. Сам inode не містить фактичних даних файлу, просто вказує на нього, тому сказати, що що-небудь переміщено з inode трохи вводить в оману. З іншого боку, журнали файлової системи зазвичай посилаються на тип журналу метаданих, який в основному використовується для захисту від збоїв.
ilkkachu

1
Звичайно, термінологія тут не головна. Важливий біт - це саме те, що ви сказали: усередині файлової системи рухатись потрібно лише дотиком до метаданих. З однієї файлової системи в іншу не існує ярлика, і всі файли потрібно переміщувати (відтворювати) один за одним, включаючи їх вміст. У такому випадку не має значення, чи переміщується весь каталог або лише файли всередині, це буде проходити так само повільно.
ilkkachu

13

Це все ще буде повільним, оскільки, як зазначалося, файлова система повинна перенаправити кожне ім'я файлу до його нового місця.

Однак ви можете пришвидшити це з того, що є у вас зараз.

Команда find запускає exec один раз для кожного файлу. Так він запускає mvкоманду 12 мільйонів разів на 12 мільйонів файлів. Це можна покращити двома способами.

  • Додайте плюс до кінця:
    find -maxdepth 1 -name '*.jpg' -exec mv -t ../../dst/ +
    Перевірте вручну сторінку, щоб переконатися, що вона підтримується у вашій версії find. Ефект повинен полягати у виконанні серії mvкоманд з такою кількістю імен файлів, скільки вміститься у кожному командному рядку.

  • Використовуйте findі xargsразом.
    find -maxdepth 1 -name '*.jpg' -print0 | xargs -0 mv -t ../../dst/
    Для -print0відокремлення імен файлів буде використано NUL, відомий як нульовий байт. Цей плюс xargs -0виправляє будь-які проблеми, які xargsб інакше виникли з пробілами у назвах файлів. xargsКоманда буде читати список імен файлів з findкомандного рядка і виконайте mvкоманду на стількох імен файлів, які помістяться.


7

Ваша плутанина пов'язана з абстракцією файлової системи, яка змушує вас повірити, що в папці містяться файли та інші папки у вигляді дерева. Це насправді не так: всі файли та каталоги в межах файлової системи розташовані на одному рівні та ототожнюються з деякими номерами, залежними від реалізації. Каталоги - це лише спеціальні файли, які містять списки інших файлів.

Коли ви "переміщуєте" файли всередині файлової системи, фактичні файли нікуди не діваються. Швидше, списки всередині каталогів оновлюються, щоб відобразити зміни.

mv src ../dstпереміщує запис одного списку з каталогу .в каталог ../dst, так що це швидко.

find -maxdepth 1 -name '*.jpg' -exec mv -t ../../dst/має перемістити мільйони записів, тому це повільніше. Це може бути пришвидшене, якщо ви зателефонуєте mvлише один раз, а не один раз на файл, а сама mvкоманда може бути оптимізована для переміщення декількох записів каталогів за один крок, але немає можливості зробити це так швидко, як при переміщенні одного каталогу .


4

Спрощена відповідь

переміщення файлу робиться в 3 етапи:

  • add () посилання на файл до списку inode цільової папки
  • перевірте, чи посилання було успішно додано
  • видаліть () посилання зі списку inode вихідної папки, якщо перевірка вище була успішною.

цей процес є однаковим для файлу чи папки.
і, очевидно, це робити для 1 файлу на 100 швидше, ніж робити це для 100 файлів.

man link є add ()
man unlink- видалити ()
mvпросто використовує ці дві команди вище та додає прапорець між ними, щоб запобігти втраті даних.


1
Ну, є також перейменувати ().
ilkkachu
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.