"cat"을 "쓸모 없이" 사용하면 성능이 향상될 수 있습니다. 왜?

"cat"을 "쓸모 없이" 사용하면 성능이 향상될 수 있습니다. 왜?

파일 1..64은 각각 160MB이며 RAM 디스크에 저장됩니다.

에 의해 생성 된:

seq 120 | parallel -k 'seq {}0000000 {}9999999 | fmt -30' | head -c 10G > 10G
parallel --pipepart --block -1 -a 10G -j 64 'cat > {#}'

nocat:

#!/bin/bash

export LC_ALL=C
sort -m \
     <(sort -m  \
            <(sort -m  \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 1; sort ) < 1) \
                                        <((rm 2; sort ) < 2) ) \
                                 <(sort -m  \
                                        <((rm 3; sort ) < 3) \
                                        <((rm 4; sort ) < 4) ) ) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 5; sort ) < 5) \
                                        <((rm 6; sort ) < 6) ) \
                                 <(sort -m  \
                                        <((rm 7; sort ) < 7) \
                                        <((rm 8; sort ) < 8) ) ) ) \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 9; sort ) < 9) \
                                        <((rm 10; sort ) < 10) ) \
                                 <(sort -m  \
                                        <((rm 11; sort ) < 11) \
                                        <((rm 12; sort ) < 12) ) ) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 13; sort ) < 13) \
                                        <((rm 14; sort ) < 14) ) \
                                 <(sort -m  \
                                        <((rm 15; sort ) < 15) \
                                        <((rm 16; sort ) < 16) ) ) ) ) \
            <(sort -m  \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 17; sort ) < 17) \
                                        <((rm 18; sort ) < 18) ) \
                                 <(sort -m  \
                                        <((rm 19; sort ) < 19) \
                                        <((rm 20; sort ) < 20) ) ) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 21; sort ) < 21) \
                                        <((rm 22; sort ) < 22) ) \
                                 <(sort -m  \
                                        <((rm 23; sort ) < 23) \
                                        <((rm 24; sort ) < 24) ) ) ) \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 25; sort ) < 25) \
                                        <((rm 26; sort ) < 26) ) \
                                 <(sort -m  \
                                        <((rm 27; sort ) < 27) \
                                        <((rm 28; sort ) < 28) ) ) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 29; sort ) < 29) \
                                        <((rm 30; sort ) < 30) ) \
                                 <(sort -m  \
                                        <((rm 31; sort ) < 31) \
                                        <((rm 32; sort ) < 32) ) ) ) ) ) \
     <(sort -m  \
            <(sort -m  \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 33; sort ) < 33) \
                                        <((rm 34; sort ) < 34) ) \
                                 <(sort -m  \
                                        <((rm 35; sort ) < 35) \
                                        <((rm 36; sort ) < 36) ) ) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 37; sort ) < 37) \
                                        <((rm 38; sort ) < 38) ) \
                                 <(sort -m  \
                                        <((rm 39; sort ) < 39) \
                                        <((rm 40; sort ) < 40) ) ) ) \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 41; sort ) < 41) \
                                        <((rm 42; sort ) < 42) ) \
                                 <(sort -m  \
                                        <((rm 43; sort ) < 43) \
                                        <((rm 44; sort ) < 44) ) ) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 45; sort ) < 45) \
                                        <((rm 46; sort ) < 46) ) \
                                 <(sort -m  \
                                        <((rm 47; sort ) < 47) \
                                        <((rm 48; sort ) < 48) ) ) ) ) \
            <(sort -m  \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 49; sort ) < 49) \
                                        <((rm 50; sort ) < 50) ) \
                                 <(sort -m  \
                                        <((rm 51; sort ) < 51) \
                                        <((rm 52; sort ) < 52) ) ) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 53; sort ) < 53) \
                                        <((rm 54; sort ) < 54) ) \
                                 <(sort -m  \
                                        <((rm 55; sort ) < 55) \
                                        <((rm 56; sort ) < 56) ) ) ) \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 57; sort ) < 57) \
                                        <((rm 58; sort ) < 58) ) \
                                 <(sort -m  \
                                        <((rm 59; sort ) < 59) \
                                        <((rm 60; sort ) < 60) ) ) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 61; sort ) < 61) \
                                        <((rm 62; sort ) < 62) ) \
                                 <(sort -m  \
                                        <((rm 63; sort ) < 63) \
                                        <((rm 64; sort ) < 64) ) ) ) ) ) |
    md5sum

withcat:

#!/bin/bash

export LC_ALL=C
sort -m \
     <(sort -m  \
            <(sort -m  \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 1; sort ) < 1) \
                                        <((rm 2; sort ) < 2) | cat) \
                                 <(sort -m  \
                                        <((rm 3; sort ) < 3) \
                                        <((rm 4; sort ) < 4) | cat) | cat) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 5; sort ) < 5) \
                                        <((rm 6; sort ) < 6) | cat) \
                                 <(sort -m  \
                                        <((rm 7; sort ) < 7) \
                                        <((rm 8; sort ) < 8) | cat) | cat) | cat) \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 9; sort ) < 9) \
                                        <((rm 10; sort ) < 10) | cat) \
                                 <(sort -m  \
                                        <((rm 11; sort ) < 11) \
                                        <((rm 12; sort ) < 12) | cat) | cat) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 13; sort ) < 13) \
                                        <((rm 14; sort ) < 14) | cat) \
                                 <(sort -m  \
                                        <((rm 15; sort ) < 15) \
                                        <((rm 16; sort ) < 16) | cat) | cat) | cat) | cat) \
            <(sort -m  \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 17; sort ) < 17) \
                                        <((rm 18; sort ) < 18) | cat) \
                                 <(sort -m  \
                                        <((rm 19; sort ) < 19) \
                                        <((rm 20; sort ) < 20) | cat) | cat) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 21; sort ) < 21) \
                                        <((rm 22; sort ) < 22) | cat) \
                                 <(sort -m  \
                                        <((rm 23; sort ) < 23) \
                                        <((rm 24; sort ) < 24) | cat) | cat) | cat) \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 25; sort ) < 25) \
                                        <((rm 26; sort ) < 26) | cat) \
                                 <(sort -m  \
                                        <((rm 27; sort ) < 27) \
                                        <((rm 28; sort ) < 28) | cat) | cat) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 29; sort ) < 29) \
                                        <((rm 30; sort ) < 30) | cat) \
                                 <(sort -m  \
                                        <((rm 31; sort ) < 31) \
                                        <((rm 32; sort ) < 32) | cat) | cat) | cat) | cat) | cat) \
     <(sort -m  \
            <(sort -m  \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 33; sort ) < 33) \
                                        <((rm 34; sort ) < 34) | cat) \
                                 <(sort -m  \
                                        <((rm 35; sort ) < 35) \
                                        <((rm 36; sort ) < 36) | cat) | cat) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 37; sort ) < 37) \
                                        <((rm 38; sort ) < 38) | cat) \
                                 <(sort -m  \
                                        <((rm 39; sort ) < 39) \
                                        <((rm 40; sort ) < 40) | cat) | cat) | cat) \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 41; sort ) < 41) \
                                        <((rm 42; sort ) < 42) | cat) \
                                 <(sort -m  \
                                        <((rm 43; sort ) < 43) \
                                        <((rm 44; sort ) < 44) | cat) | cat) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 45; sort ) < 45) \
                                        <((rm 46; sort ) < 46) | cat) \
                                 <(sort -m  \
                                        <((rm 47; sort ) < 47) \
                                        <((rm 48; sort ) < 48) | cat) | cat) | cat) | cat) \
            <(sort -m  \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 49; sort ) < 49) \
                                        <((rm 50; sort ) < 50) | cat) \
                                 <(sort -m  \
                                        <((rm 51; sort ) < 51) \
                                        <((rm 52; sort ) < 52) | cat) | cat) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 53; sort ) < 53) \
                                        <((rm 54; sort ) < 54) | cat) \
                                 <(sort -m  \
                                        <((rm 55; sort ) < 55) \
                                        <((rm 56; sort ) < 56) | cat) | cat) | cat) \
                   <(sort -m  \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 57; sort ) < 57) \
                                        <((rm 58; sort ) < 58) | cat) \
                                 <(sort -m  \
                                        <((rm 59; sort ) < 59) \
                                        <((rm 60; sort ) < 60) | cat) | cat) \
                          <(sort -m  \
                                 <(sort -m  \
                                        <((rm 61; sort ) < 61) \
                                        <((rm 62; sort ) < 62) | cat) \
                                 <(sort -m  \
                                        <((rm 63; sort ) < 63) \
                                        <((rm 64; sort ) < 64) | cat) | cat) | cat) | cat) | cat) | cat |
    md5sum

유일한 차이점은 withcat모든 것이 sort -m로 파이프된다는 것입니다 cat.

"고양이의 쓸모없는 이용" - 사람들은 당신 withcat이 보다 느리게 믿게 만들 것입니다 nocat. 그러나 그 반대가 사실입니다.

$ time bash nocat
c933d81faea7b8dec8eb64ca0b044d74  -

real    3m40.854s
user    2m48.687s
sys     0m49.135s
$ time bash withcat
c933d81faea7b8dec8eb64ca0b044d74  -

real    2m21.812s
user    2m16.651s
sys     1m36.135s

이 테스트는 64코어 시스템에서 실행되며 다른 작업은 수행하지 않습니다. 모든 것이 RAM에 있습니다(따라서 디스크 속도가 느려서가 아닙니다). 각 테스트는 3회 실행되었으며 가장 좋은 시간은 위에 나와 있습니다. 세 가지 테스트 모두 가장 좋은 시간으로부터 5초 이내에 완료되었습니다(그래서 이는 우연이 아니었습니다).

출력을 파이프하는 것이 더 빠른 이유는 무엇입니까 cat?

편집하다

그룹 입력이 cat더 커질까요? 그리고/또는 sort각 라인의 출력을 플러시하시겠습니까?

이것을 테스트하기 위해 다음을 시도했습니다.

$ strace -ff sort -m <(sort 1) <(sort 2) 2>fromsort | cat >/dev/null
$ strace -ff sort -m <(sort 1 | cat ) <(sort 2 | cat) 2>fromcat | cat >/dev/null

cat더 큰 청크로 분할되면 더 read큰 청크가 반환될 것으로 예상됩니다. 하지만 그렇지 않습니다:

$ grep -E 'read|write' fromsort |field 1,5|sort | uniq -c 
      1 openat(AT_FDCWD,        3
      8 pread64(3,      =
      1 read(3, 3771
  40989 read(3, 4096
      2 read(3, 832
      1 read(3, unknown
      1 read(4, 0
      1 read(4, 2241
  40959 read(4, 4096
      1 write(1,        1916
  81949 write(1,        4096
$ grep -E 'read|write' fromcat |field 1,5|sort | uniq -c 
      1 openat(AT_FDCWD,        3
      8 pread64(3,      =
      1 read(3, 3771
  40989 read(3, 4096
      2 read(3, 832
      1 read(3, unknown
      1 read(4, 2241
  40959 read(4, 4096
      1 read(4, unknown
      1 write(1,        1916
  81949 write(1,        4096

두 경우 모두 read합은 write4K입니다.

(그런데,sort 하다파이프가 아닌 파일에서 읽는 경우 (더 많은) 더 큰 청크를 읽지만 여기서는 그렇지 않습니다.

편집 2

위의 목적은 추가가 cat항상 쓸모없는 것은 아니라는 것을 보여주고 이것이 사실인 이유를 알아내는 것입니다.

목표는 데이터를 정렬하는 것이 아닙니다.

하지만 목표라면예전에는sort데이터를 정렬하려면 내장된 데이터를 사용하면 어떨까요 --parallel?

64코어 ​​머신에서 기본적으로 사용되는 sort것 같습니다 . CPU의 최대 800%를 사용하고 있음을 보여줍니다. 64개의 코어를 사용하도록 강제할 수 있습니다 .--parallel 8top--parallel 64

$ time sort {1..64} | md5sum
real    9m4.005s
user    29m56.454s
sys     5m49.560s

$ time sort --parallel 64 {1..64} | md5sum
real    6m50.332s
user    35m55.040s
sys     11m37.609s

따라서 GNU 정렬은 --parallel위의 정렬보다 훨씬 느립니다. 이제 위 콘텐츠를 사용할 수 있습니다 parsort.http://git.savannah.gnu.org/cgit/parallel.git/tree/src/parsort

답변1

이는 결코 '고양이의 쓸데없는 행동'이 아니다.

some_command | cat | some_command

이는 전통적인 의미에서 "고양이의 막다른 골목"이 아니며 일반적으로 인클로저에 대한 무지에서 발생합니다. 대신에 고양이의 역동성을 가지고 뭔가를 하려는 고의적인 시도처럼 보입니다. 이 경우에는 캐시라고 생각합니다.


내 두 번째 생각

읽기와 쓰기의 크기에 차이가 없더라도 감지할 수 없는 무언가가 작용할 수 있습니다.

첫째(매우 중요함):정렬되지 않은 배열보다 정렬된 배열을 처리하는 것이 더 빠른 이유는 무엇입니까?. CPU가 이 작업을 처리하는 순서를 변경하면 타이밍이 변경될 수 있습니다. 중단(및 다른 프로세스로 전환)하지 않고 cat각 실행 시간을 더 길게 만드는 데 성공 하면 sort이는 CPU의 분기 예측에 큰 영향을 미치고 시간이 더 길어지거나 짧아질 수 있습니다.

둘째, 읽기 수와 크기가 영향을 받지 않더라도 작업을 일시 중지(차단)해야 하는 횟수는 다를 수 있습니다. 이는 그 자체로 오버헤드를 늘리거나 줄일 수 있습니다. 따라서 읽기와 쓰기의 크기가 동일하더라도 (캐싱) 계층은 cat시간당 읽기 및 쓰기 횟수를 줄일 수 있습니다.read()write()

Cat은 정렬을 더 오래 기다리게 하여 중단 없이 더 많은 작업을 수행하고 각 프로세스가 차단되는 횟수를 줄일 수 있습니다. 이는 감지하기 어려울 것입니다.


나의 첫 생각

내 기대는 두 버전을 자체 스크립트에 넣고 strace -f각각에서 실행하면 cat을 사용한 예제에서 읽기 또는/쓰기 호출이 더 적어질 것이라는 것입니다. 최소한 cat. sort​사실, 나는 그것이 read()충분히 큰 블록에 있지만 write()단일 행에만 있기를 원합니다. 이는 자체적으로 배관되도록 설계되지 않았음을 의미합니다.

락탁이 지적했듯이그의 대답, cat은 128KB 청크로 읽습니다(이봐) 그러나 파이프는 일반적으로 64KB만 버퍼링합니다. 내 생각이 맞다면 cat이 read()완료되기를 기다리는 동안 sort정지하지 않고 쓸 수 있는 큰(128 + 64KB) 버퍼를 쓰기 작업에 제공하게 됩니다. 복구될 때쯤에는 다음 쓰기로 전달할 cat데이터가 많아집니다( sort단일 쓰기로 전송된 것보다 훨씬 더 많음) sort. 그래서 다음 사람은 sort멈추지 않고 그 내용을 많이 읽을 수 있습니다.

나도 의심한다다음에 추가가장 가까운 파일 계층은 cat성능에 거의 또는 전혀 영향을 미치지 않습니다. 이러한 파일은 이미 RAM 디스크에 캐시되어 있습니다. 그러나 호출 사이의 레이어는 sort버퍼 역할을 하므로 그 수를 줄여야 합니다. 이것은 실제로 "cat의 쓸모없는 사용", 즉 cat을 사용하여 파일을 읽는 상황입니다. 이는 다음과 같은 형태입니다.

cat some_file | some_command

흥미로운 실험

파이프의 버퍼 크기를 늘려서 동일한 효과를 얻을 수 있는지 알고 싶습니다. 올바른 프로그래밍 언어(셸이 아님)를 사용하여 동일한 파이프를 설정하는 경우. 예를 들어 C에서는 , pipe(), dup2()를 사용하여 파이프를 생성하고 각 파이프를 fork()먼저 호출하여 버퍼 크기를 늘릴 수 있습니다(참조:exec()ioctl()파이프 용량)

답변2

내 생각엔 cat을 사용하면 각 명령의 처리량이 제한되어 명령이 병렬로 더 빠르게 실행되는 것 같습니다.

cat데이터 읽기128KB 청크. 귀하의 테스트를 재현할 수 없으므로 귀하의 사용법을 바꾸어 제가 옳고 그른지 증명할 cat수 있습니까?dd

dd status=none bs=128K동일한 효과가 있어야 합니다 cat. 청크 크기를 늘리거나 줄이고 결과를 비교해 보세요.

관련 정보