Perché lo spostamento di alcuni file in una cartella richiede più tempo rispetto allo spostamento dell'intera cartella?


21

Ho milioni di immagini sul mio server cloud Ubuntu. Quando sposto una cartella completa contenente 12 milioni di immagini usando il mvcomando, succede quasi istantaneamente. Tuttavia, quando ho mvsolo immagini (non la cartella), allora ci vuole un po 'di tempo. C'è un modo per spostare tutte le immagini velocemente come le cartelle?

Questo è ciò che sta succedendo:

  1. la cartella src ha 12 milioni di immagini e lo sposto nella cartella dst usando

    $ mv  src ../dst
    

    Succede immediatamente

  2. Nella cartella src lo faccio per spostare:

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

    Questo richiede del tempo.

C'è un modo per accelerare il secondo processo?


1
Non una soluzione, ma per chiarire: cmd2 deve essere più lento di cmd1 poiché utilizza find e quindi esegue lo spostamento per il risultato. Questo non può mai essere veloce come una mossa diretta senza il processo di pre-ricerca.
dufte,

probabilmente dstè in una partizione mentre ../../dstè su un'altra.
phuclv,

Come scritto, questo non sembra nemmeno un invito a trovare valido. Manca qualsiasi {}argomento in cui il nome del file verrà espanso.
R ..

Ho inviato una modifica che altera il titolo, rimuovendo il riferimento alle "immagini" e sostituendolo con il nocciolo della questione: sta spostando i singoli file anziché spostare l'intera cartella. Spero che sia accettato da qualcuno con il rappresentante di farlo.
Monty Harder,

1
Non è una valida invocazione di find. find ... -exec mv -t ../../dst/ {} \;chiamerebbe mvuna volta per file; find ... -exec mv -t ../../dest {} +sarebbe molto più veloce, copiando il maggior numero possibile di file per chiamata, ma non tanto velocemente quanto spostando la directory stessa come spiegato da dadexix86 .
Chepner,

Risposte:


50

TL; DR : No

Per una quantità minore di file, non sarebbe necessario findma, anche in questo caso semplificato e più piccolo, se solo

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

ci vorrà più tempo che spostare l'intera directory in una volta.


Perché? Il punto è capire cosa mvfa.

In breve, mvsposta un numero (che identifica una directory o un file) da un inode (la directory che lo contiene) a un altro e questi indici vengono aggiornati nel journal del file system o nel FAT (se il file system è implementato in questo modo).

Se l'origine e la destinazione si trovano sullo stesso file system, non vi è alcun movimento effettivo di dati, cambia solo la posizione, il punto in cui sono collegati.

Quindi, quando si esegue mv una directory, si esegue questa operazione una volta .

Ma quando sposti 1 milione di file, esegui questa operazione 1 milione di volte .

Per darti un esempio pratico, hai un albero con molti rami. In particolare, esiste un nodo a cui sono collegati 1 milione di rami.
Per tagliare questi rami e spostarli da qualche altra parte, puoi tagliare ognuno di essi, in modo da fare 1 milione di tagli o tagliare appena prima del nodo, facendo così un solo taglio (questa è la differenza tra spostare i file e la directory).


4
Dovresti includere che a mvsullo stesso filesystem è solo una riscrittura della voce TOC.
Videonauth,

Non sono sicuro di aver capito cosa intendi per TOC. Per quanto ne so, non esiste una tabella nei file system ext, NTFS, btrfs e così via. FAT ha una tabella (da cui prende il nome) ma ad esempio ext memorizza nomi e blocchi, genitori, figli e altre informazioni negli inode. Se puoi indicarmi un riferimento in cui viene spiegato dove ext FS ha il loro sommario e a cosa serve, leggerò volentieri e aggiornerò la risposta :)
dadexix86

10
Um. mv *.jpgrischia di fallire per 12 milioni di file, motivo per cui usa find. La maggior parte degli Unix, incluso Linux, credo (a meno che qualcuno non l'abbia cambiato negli ultimi 5-10 anni) abbia una lunghezza massima limitata della riga di comando. Penso che sia stato 64K per Linux per molto tempo. Lo stesso limite si applica alle variabili d'ambiente, ne sono abbastanza sicuro.
Zan Lynx,

1
Lo spostamento di un file riguarda più lo spostamento del suo nome . Le voci di directory simili a Unix contengono un nome file e un numero di inode, che è fondamentalmente un puntatore al resto dei metadati. Una directory è solo un tipo speciale di file. L'inode stesso non contiene i dati effettivi del file, solo dei puntatori ad esso, quindi è un po 'fuorviante dire che qualsiasi cosa viene spostata da un inode. D'altra parte, le riviste del file system di solito fanno riferimento a un tipo di registro dei metadati utilizzato principalmente per la protezione dagli arresti anomali.
ilkkachu,

1
Naturalmente, la terminologia non è il punto principale qui. Il bit importante è esattamente quello che hai detto: all'interno di un filesystem, una mossa deve solo toccare i metadati. Da un filesystem all'altro, non esiste alcun collegamento e tutti i file devono essere spostati (ricreati) uno per uno, incluso il loro contenuto. In quel caso, non importa se si sta spostando l'intera directory o solo i file all'interno, sarà altrettanto lento.
ilkkachu,

13

Sarà comunque lento perché, come notato, il file system deve ricollegare ogni nome di file nella nuova posizione.

Tuttavia, puoi accelerarlo da quello che hai ora.

Il comando find esegue exec una volta per ogni file. Quindi avvia il mvcomando 12 milioni di volte per 12 milioni di file. Questo può essere migliorato in due modi.

  • Aggiungi un vantaggio alla fine:
    find -maxdepth 1 -name '*.jpg' -exec mv -t ../../dst/ +
    controlla la pagina man per assicurarti che sia supportata nella tua versione di find. L'effetto dovrebbe essere quello di eseguire una serie di mvcomandi con tutti i nomi di file che rientrano in ciascuna riga di comando.

  • Usa finde xargsinsieme.
    find -maxdepth 1 -name '*.jpg' -print0 | xargs -0 mv -t ../../dst/
    Il -print0utilizzerà NUL, aka zero byte per separare i nomi dei file. Questo plus xargs -0risolve eventuali problemi xargsche altrimenti avrebbero con gli spazi nei nomi dei file. Il xargscomando leggerà l'elenco dei nomi dei file dal findcomando ed eseguirà il mvcomando su tutti i nomi file adatti.


7

La tua confusione deriva dall'astrazione del file system che ti fa credere che una cartella contenga file e altre cartelle in modo simile ad un albero. Questo in realtà non è vero: tutti i file e le directory all'interno di un file system si trovano sullo stesso livello e identificati con numeri di qualche tipo, a seconda dell'implementazione. Le directory sono solo file speciali che contengono elenchi di altri file.

Quando "sposti" i file all'interno di un file system, i file effettivi non vanno da nessuna parte. Piuttosto, gli elenchi all'interno delle directory vengono aggiornati per riflettere la modifica.

mv src ../dstsposta una singola voce dell'elenco da una directory .all'altra ../dst, quindi è veloce.

find -maxdepth 1 -name '*.jpg' -exec mv -t ../../dst/deve spostare milioni di voci, quindi è più lento. Potrebbe essere potenzialmente accelerato se si chiama mvsolo una volta e non una volta per file e il mvcomando stesso può essere ottimizzato per spostare più voci della directory in un solo passaggio, ma non c'è modo di renderlo veloce come quando si sposta una singola directory .


4

Una risposta semplificata

lo spostamento di un file è fatto in 3 passaggi:

  • aggiungere () un collegamento al file all'elenco di inode della cartella di destinazione
  • controlla se il link è stato aggiunto correttamente
  • rimuovere () il collegamento dall'elenco degli inode della cartella di origine se il controllo sopra riportato ha avuto esito positivo.

questo processo è lo stesso per un file o una cartella.
e ovviamente farlo per 1 file è 100 più veloce di farlo per 100 file.

man link è il add ()
man unlinkè il remove ()
mvusa solo quei due comandi sopra e aggiunge un segno di spunta per impedire la perdita di dati.


1
Bene, c'è anche rename ().
ilkkachu,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.