"xargs ls"를 병렬로 실행할 때 잘못된 출력

"xargs ls"를 병렬로 실행할 때 잘못된 출력

/usr/사용 중인 모든 파일을 나열하고 싶습니다 ls. ls직접 전화하는 대신 xargs. 또한 xargs매개변수를 사용 -L하고 -P모든 코어를 활용하고 있습니다.

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

위 명령은 예상대로 작동합니다. 좋은 출력을 만들어냅니다. 그러나 행 매개변수 수를 -L16에서 64로 늘리면 다음과 같습니다 .

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

결과 출력은 모두 횡설수설입니다. 내 말은 출력이 더 이상 새 줄에서 시작되지 않고 새 줄이 "이전 줄"의 중간에서 시작되며 모두 함께 혼합된다는 것입니다.

-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

흥미롭게도 이는 -L64이상을 사용할 때만 발생합니다. 이 문제는 보이지 않습니다 -L16.

여기서 무슨 일이 일어나고 있는지 설명할 수 있는 사람이 있나요?

답변1

이는 파이프에 쓰는 것과 관련이 있습니다. 16개 파일마다 하나의 프로세스를 실행 하므로 -L16파일 이름 길이에 따라 약 1000자가 됩니다. 당신 과 함께있는 사람은 약 4 천명입니다 -L64. 이 ls프로그램은 거의 확실하게 stdio 라이브러리를 사용하고 쓰기 호출 수를 줄이기 위해 출력에 4kB 버퍼를 사용하는 것이 거의 확실합니다.

따라서 find는 많은 수의 파일 이름을 생성한 다음 (-L64의 경우) xargs를 64개의 파일 이름으로 분할하고 ls이를 처리하기 위해 4개의 프로세스를 시작합니다. 각각은 ls첫 번째 4k 출력을 생성하고 정렬을 위해 파이프라인에 씁니다. 이 4k는 일반적으로아니요개행 문자로 끝납니다. 따라서 세 번째가 ls먼저 첫 번째 4kB를 준비한 다음 종료한다고 가정해 보겠습니다.

 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

그런 다음 첫 번째 ls는 다음과 같은 것을 출력합니다.

 total 123459

그런 다음 정렬된 입력에는 다음이 포함됩니다.lrwxrwxrwx 1 root root 6 Oct 2total 123459

-L16경우 ls프로세스는 (일반적으로) 한 번에 전체 결과 세트만 출력합니다.

물론, 이 경우 xargs와 ls를 사용하는 것은 시간과 자원의 낭비일 뿐이며, find정보를 다시 찾기 위해 추가 프로그램을 실행하는 것이 아니라 이미 가지고 있는 정보를 출력하기만 하면 됩니다.

답변2

GNU Parallel은 혼합 문제를 정확하게 해결하기 위해 만들어졌습니다(실행 시간 40초):

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

코어 수(실행 시간 40초)도 감지합니다.

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

입력을 균등하게 분할합니다(실행 시간 24초).

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

관련 정보