saída adulterada ao executar "xargs ls" em paralelo

7

Eu quero listar todos os arquivos em /usr/ usando ls . Eu não estou chamando ls diretamente, mas via xargs . Além disso, estou usando xargs parameters -L e -P para utilizar todos os meus núcleos.

find /usr/ -type f  -print0 | xargs -0 -L16 -P4 ls -lAd  | sort -k9 > /tmp/aaa

o comando acima funciona como esperado. Produz saída legal. No entanto, quando eu aumentar o número de linhas -L parâmetro de 16 a 64:

find /usr/ -type f  -print0 | xargs -0 -L64 -P4 ls -lAd  | sort -k9 > /tmp/bbb

a saída resultante é toda distorcida. O que quero dizer com isso é que a saída não começa mais na nova linha, as novas linhas começam no meio da linha "anterior" e estão todas misturadas:

-rw-r--r-- 1 root root  5455 Nov 16  2010 /usr/shareonts/X11/encodings/armscii-8.enc.gz
-rw-r--r-- 1 root root  1285 May 29  2016-rw-r--r-- 1 root root   6205 May 29  2016 /usr/include/arpa/nameser_compat.h
-rw-r--r-- 1 root root       0 Apr 17  20-rw-r--r-- 1 root root   933 Apr 16  2012 /usr/share/icons/nuoveXT2/16x16/actions/address-book-new.png
-rw-r--r-- 1 root root  53651 Jun 17  2012-rw-r--r-- 1 root root  7117 May 29  2016 /usr/include/dlfcn.h
-rw-r--r-- 1 root root  311 Jun  9  2015-rw-r--r-- 1 root root 1700 Jun  9  2015 /usr/share/cups/templates/de/add-printer.tmpl
-rw-r--r-- 1 root root  5157 M1 root root 10620 Jun 14  2012 /usr/lib/perl5/Tk/pTk/tkIntXlibDecls.m
-rw-r--r-- 1 root -rwxr-xr-x 1 root root    1829 Jan 22  2013 /usr/lib/emacsen-common/packages/install/dictionaries-common
-rw-r--r-- 1 root r-rw-r--r-- 1 root root  1890 Jun  2  2012 /usr/share/perl5/Date/Manip/TZ/afaddi00.pm
-rw-r--r-- 1 root root 1104 Jul-rw-r--r-- 1 root root  10268 Jul 27 15:58 /usr/share/perl/5.14.2/B/Debug.pm
-rw-r--r-- 1 root root  725 Apr  1-rw-r--r-- 1 root root  883 Apr  1  2012 /usr/share/icons/gnome/16x16/actions/address-book-new.png

O engraçado é que isso só acontece quando usamos -L64 ou maior. Eu não vejo esse problema com -L16 .

Alguém pode explicar o que está acontecendo aqui?

    
por Martin Vegter 23.12.2016 / 23:07

2 respostas

5

Isso tem a ver com gravações em pipes. Com -L16 você está executando um processo para cada 16 arquivos, o que produz cerca de mil caracteres, dependendo de quanto tempo os nomes de arquivos estão. Com -L64 você é cerca de quatro mil. O programa ls quase certamente usa a biblioteca stdio, e quase certamente usa um buffer de 4kB para gerar uma saída para reduzir o número de chamadas de gravação.

Portanto, find produz uma carga de nomes de arquivos e, em seguida, (para o caso -L64) os xargs os dividem em pacotes de 64 e iniciam 4% de processosls para manipulá-los. Cada ls gerará seus primeiros 4k de saída e os gravará no pipe para classificar. Note que este 4k tipicamente não terminará com uma nova linha. Então diga que o terceiro ls obtém seu primeiro 4kB pronto primeiro e termina

 lrwxrwxrwx 1 root root       6 Oct 21  2013 bzegrep -> bzgrep
 -rwxr-xr-x 1 root root    4877 Oct 21  2013 bzexe
 lrwxrwxrwx 1 root root       6 Oct 2

e depois o primeiro ls produz algo, por ex.

 total 123459

a entrada para classificar incluirá lrwxrwxrwx 1 root root 6 Oct 2total 123459

No caso -L16 , os processos ls (normalmente) só geram um conjunto completo de resultados de uma só vez.

É claro que para este caso você está apenas desperdiçando tempo e recursos usando xargs e ls, você deve deixar find mostrar as informações que já tem em vez de executar programas extras para descobrir as informações novamente.

    
por 24.12.2016 / 00:09
1

O GNU Parallel foi construído para resolver exatamente o problema de mixagem (tempo de execução de 40 segundos):

find /usr/ -type f  -print0 | parallel -0 -L64 -P4 ls -lAd  | sort -k9 > /tmp/bbb

Pode até detectar o número de núcleos (tempo de execução de 40 segundos):

find /usr/ -type f -print0 | parallel -0 -L64 ls -lAd  | sort -k9 > /tmp/bbb

E divida a entrada uniformemente (tempo de execução 24 segundos):

find /usr/ -type f -print0 | parallel -0 -X ls -lAd  | sort -k9 > /tmp/bbb
    
por 04.03.2017 / 12:09

Tags