일반적인 Linux 배포판에서 , rm
, , 등과 mv
같은 유틸리티는 해당 인수와 병렬로 실행됩니까 ?ls
grep
wc
즉, grep
32스레드 CPU에서 대용량 파일을 처리하면 듀얼코어 CPU보다 더 빠르게 실행될까요?
답변1
유틸리티가 라이브러리와 연결되어 있는지 확인하면 첫인상을 알 수 있습니다 pthread
. 운영 체제 스레드를 사용하는 동적으로 링크된 프로그램은 pthread 라이브러리를 사용해야 합니다.
ldd /bin/grep | grep -F libpthread.so
우분투를 예로 들어 보겠습니다.
for x in $(dpkg -L coreutils grep findutils util-linux | grep /bin/); do if ldd $x | grep -q -F libpthread.so; then echo $x; fi; done
그러나 프로그램 자체가 pthread와 연결되어 있는 라이브러리와 연결되어 있기 때문에 많은 수의 오탐이 발생합니다. 예를 들어, /bin/mkdir
내 시스템에서는 자체적으로 pthread와 연결되는 PCRE(이유는 모르겠습니다...)와 연결됩니다. 그러나 mkdir
어떤 식으로든 병렬화되지는 않았습니다.
실제로는 실행 파일이 포함되어 있는지 확인하는 것이 libpthread
더 신뢰할 수 있는 결과를 제공합니다. 병렬 동작이 라이브러리에 완전히 포함되어 있는 실행 파일이 누락될 수 있지만 기본 유틸리티는 일반적으로 그런 방식으로 설계되지 않습니다.
dpkg -L coreutils grep findutils util-linux | grep /bin/ | xargs grep pthread
Binary file /usr/bin/timeout matches
Binary file /usr/bin/sort matches
따라서 실제로 병렬화할 수 있는 유일한 도구는 입니다 sort
. ( timeout
librt에 연결되므로 libpthread에만 연결됩니다.) GNU는 sort
병렬로 작동합니다. 스레드 수는 다음과 같이 구성할 수 있습니다.--parallel
옵션, 기본적으로 프로세서당 하나의 스레드를 사용하여 최대 8개까지 가능합니다. (프로세서 수가 증가하면 더 많은 프로세서를 사용하는 이점이 줄어듭니다., 점진적인 감소 속도는 작업의 병렬화 정도에 따라 달라집니다. )
grep
병렬화가 전혀 없습니다. PCRE 라이브러리는 잠금을 사용하는 스레드로부터 안전한 기능을 제공하고 잠금 작업 기능이 pthread 라이브러리에 있기 때문에 실제로 pthread 라이브러리에 연결됩니다.
대량의 데이터를 처리할 때 일반적으로 병렬화의 이점을 누릴 수 있는 간단한 방법은 데이터를 여러 조각으로 분할한 다음 해당 조각을 병렬로 처리하는 것입니다. grep의 경우 파일 크기를 제어 가능하게 유지하고(예: 로그 파일인 경우 충분히 자주 회전) 각 파일에서 별도의 grep 인스턴스를 호출합니다(예: 다음을 사용하여)GNU 병렬). grepping은 일반적으로 IO 바운드(또는 매우 복잡한 정규 표현식이 있거나 GNU grep(성능 저하)의 일부 유니코드 코너 사례가 발생하는 경우 CPU 바운드)이므로 스레드가 많아도 많은 이점을 얻을 가능성이 없습니다.
답변2
알아내는 또 다른 방법은 sysdig
프로세스에서 실행되는 시스템 호출을 검사하는 것과 같은 것을 사용하는 것입니다. 예를 들어, rm
(시스템 호출을 통해) 스레드가 생성되었는지 확인하려면 clone
다음을 수행하면 됩니다.
# sysdig proc.name=rm and evt.type=clone and evt.dir='<'
이 실행을 통해 나는 다음을 수행했습니다.
$ mkdir foo
$ cd foo
$ touch {1..9999}
$ rm *
클론이 보이지 않습니다. 스레드가 없습니다. 다른 도구를 사용하여 이 실험을 반복할 수 있지만 스레드가 있는 것을 발견할 수는 없을 것 같습니다.
이는 clone()
의 기본 이기도 fork()
하므로 도구가 다른 프로세스(예 find ... -exec
: )를 시작하면 이 출력이 표시됩니다. 이러한 플래그는 "새 스레드 만들기" 사용 사례와 다릅니다.
# sysdig proc.name=find and evt.type=clone and evt.dir='<'
...
1068339 18:55:59.702318832 2 find (2960545) < clone res=0 exe=find args=/tmp/foo.-type.f.-exec.rm.{}.;. tid=2960545(find) pid=2960545(find) ptid=2960332(find) cwd= fdlimit=1024 pgft_maj=0 pgft_min=1 vm_size=9100 vm_rss=436 vm_swap=0 comm=find cgroups=cpuset=/.cpu=/user.slice.cpuacct=/user.slice.io=/user.slice.memory=/user.slic... flags=25165824(CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID) uid=1026 gid=1026 vtid=2960545(find) vpid=2960545(find)
답변3
병렬로 실행하는 방법은 xargs
또는 gnu를 참조하세요 .parallel
그러나 더 많은 프로세스가 추가될수록 병렬화 가능한 부분은 시간이 0이 되는 경향이 있습니다. 이렇게 하면 병렬화할 수 없는 부분이 남게 되어 속도가 더 빨라지지 않습니다. 따라서 프로세스를 더 추가하여 작업을 완료하는 속도에는 한계가 있습니다. 머지않아 프로세스를 추가해도 별 차이가 없는 상황에 도달하게 될 것입니다.
그런 다음 통신 오버헤드가 있습니다. 프로세스를 추가하면 속도가 느려집니다. 프로세스 추가에 따른 이점이 프로세스 추가 비용보다 적으면 프로세스 속도가 느려질 수 있습니다.
답변4
기본적으로 지정한 유틸리티에 관심이 있는 경우 이러한 명령의 스레드 버전이 존재할 가능성은 거의 없습니다.
더 나쁜 것은 이 변형이 존재한다면 단일 스레드 버전보다 속도가 느릴 가능성이 높다는 것입니다.
이는 귀하가 명명한 유틸리티가 모두 (여러 스레드에서 수행되는 경우) 커널 최적화(예: 미리 읽기)를 손상시킬 수 있는 많은 파일 시스템 상호 작용을 가지고 있기 때문입니다.
예를 들어 잘 구현된 커널은 파일의 선형 읽기를 감지하고 예를 들어 grep
파일 내용을 미리 가져와서 선형 읽기를 발생시킵니다.grep
작업은 하나 또는 두 개의 디렉터리에서 mv
이루어지며 rename
커널에 디렉터리 잠금이 필요합니다. 비원자적 방식으로 구현되지 않는 한 이러한 디렉터리에 대한 또 다른 이름 바꾸기 작업은 동시에 발생할 수 없습니다.
반면, 가장 오래된 무료 tar
구현( )은 두 가지 기본 작업 측면에서 30년 동안 병렬화되어 왔습니다. 두 프로세스가 있고 두 프로세스 사이에 공유 메모리 블록이 있어 하나의 프로세스가 아카이브 읽기/쓰기 작업을 수행할 수 있습니다. star
파일 시스템 I/O를 수행하는 동안 다른 프로세스가 아카이브 읽기/쓰기 작업을 수행할 수 있습니다 .
grep
커널의 파일 시스템 프리페칭은 단일 CPU를 사용하는 것보다 여러 CPU를 사용하는 것이 더 빠르기 때문에 특정 질문 에 "대부분 예"라고 답할 수 있습니다. 작업 중인 파일이 그다지 크지 않고 파일이 이미 커널 캐시 내에 있는 경우 프리페치 이점이 없습니다.
time
참고: 최신 쉘에는 시간을 표시할 뿐만 아니라 벽시계 시간에 대한 USER 및 SYS CPU 시간의 합계 비율을 기준으로 백분율을 계산하는 내장 기능이 있습니다 . 관련 time
출력이 100%를 초과하면 실행 중인 유틸리티가 실제로 여러 CPU를 활용하고 있는 것입니다. 그러나 스레드되지 않은 유틸리티의 경우 값은 일반적으로 약 105%입니다.
마지막으로 병렬화는 프로세스 수준에서도 발생하며 병렬화된 버전은 make
비병렬화된 버전보다 쉽게 3배 빠르게 실행될 수 있습니다.
플랫폼에서 실행 중에 CPU를 종료할 수 있는 경우 CPU를 종료 n-1
하고 결과를 동일한 시스템의 다른 다중 CPU 환경과 비교해 보는 것이 좋습니다.