!["xargs ls"를 병렬로 실행할 때 잘못된 출력](https://linux55.com/image/101635/%22xargs%20ls%22%EB%A5%BC%20%EB%B3%91%EB%A0%AC%EB%A1%9C%20%EC%8B%A4%ED%96%89%ED%95%A0%20%EB%95%8C%20%EC%9E%98%EB%AA%BB%EB%90%9C%20%EC%B6%9C%EB%A0%A5.png)
/usr/
사용 중인 모든 파일을 나열하고 싶습니다 ls
. ls
직접 전화하는 대신 xargs
. 또한 xargs
매개변수를 사용 -L
하고 -P
모든 코어를 활용하고 있습니다.
find /usr/ -type f -print0 | xargs -0 -L16 -P4 ls -lAd | sort -k9 > /tmp/aaa
위 명령은 예상대로 작동합니다. 좋은 출력을 만들어냅니다. 그러나 행 매개변수 수를 -L
16에서 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