bash 스크립트 최적화 처리 속도

bash 스크립트 최적화 처리 속도

Bash 스크립트를 최적화하기 위한 일반적인 지침이 있는지 궁금합니다.

  • 예를 들어, 그것은 더편리한명령줄 대신 루프를 작성하지만, 이는 또한더 빠른 처리시스템을 위해서? 예:

    for i in a b c; do echo $i; done
    
    echo a
    echo b
    echo c
    
  • 때때로 사람들은 동일한 문제에 대해 서로 다른 해결책을 생각해냅니다. 예를 들어, sed, cutawkecho모두 문자열에서 숫자를 제거할 수 있습니다. 다음 코드를 사용하면 숫자가 낮을수록 속도가 빨라진다고 말할 수 있는지 궁금합니다.

    1. 같은 명령

      STRING=abc.def
      echo ${STRING} | sed 's/.def//g'
      echo ${STRING} | sed '$s/....$//'
      
    2. 다음과 같은 다른 명령

      STRING=abc.def
      echo ${STRING} | cut -d . -f 1
      echo ${STRING} | sed 's/.def//g'
      

답변1

최적화의 첫 번째 규칙은 다음과 같습니다.최적화되지 않음. 먼저 테스트해보세요. 테스트 결과 프로그램이 너무 느린 것으로 나타나면 가능한 최적화 방법을 찾아보세요.

확실히 알 수 있는 유일한 방법은 사용 사례를 벤치마킹하는 것입니다. 몇 가지 일반적인 규칙이 있지만 일반적인 애플리케이션의 일반적인 데이터 양에만 적용됩니다.

특정 상황에서는 일부 일반 규칙이 적용되거나 적용되지 않을 수 있습니다.

  • 셸 내부 처리의 경우 ATT ksh가 가장 빠릅니다. 문자열 조작을 많이 한다면 ATT ksh를 사용하세요. Dash가 2위이고 bash, pdksh 및 zsh가 뒤쳐져 있습니다.
  • 한 번에 짧은 작업을 수행하기 위해 셸을 자주 호출해야 하는 경우 시작 시간이 짧기 때문에 대시가 승리합니다.
  • 외부 프로세스를 시작하는 데는 시간이 걸리므로 복잡한 부분이 포함된 파이프라인을 갖는 것이 루프의 파이프라인보다 빠릅니다.
  • echo $fooecho "$foo"큰따옴표가 없으면 $foo단어로 나누어 각 단어를 파일 이름 와일드카드 패턴으로 해석하기 때문에 그보다 느립니다 . 게다가 이러한 분할 및 와일드카드 동작은 거의 필요하지 않습니다. 따라서 변수 대체 및 명령 대체에는 항상 큰따옴표를 넣어야 한다는 점을 기억하십시오: "$foo", "$(foo)".
  • 특수 목적 도구는 종종 범용 도구보다 성능이 뛰어납니다. 예를 들어, cut또는 같은 도구를 head사용하여 시뮬레이션할 수 있지만 sed속도 sed가 느려지거나 더 느려집니다 awk. 쉘 문자열 처리는 느리지만 짧은 문자열의 경우 외부 프로그램을 호출하는 것보다 성능이 훨씬 뛰어납니다.
  • Perl, Python 및 Ruby와 같은 고급 언어를 사용하면 더 빠른 알고리즘을 작성할 수 있는 경우가 많지만 시작 시간이 훨씬 길기 때문에 많은 양의 데이터로 작업하는 경우에만 수행할 가치가 있습니다.
  • 적어도 Linux에서는 파이프가 임시 파일보다 빠른 경향이 있습니다.
  • 쉘 스크립트의 대부분의 사용은 I/O 집약적인 프로세스를 중심으로 이루어지므로 CPU 소비는 중요하지 않습니다.

성능 문제는 쉘 스크립트에서 거의 고려되지 않습니다.위 목록은 순전히 예시용입니다. 대부분의 경우 차이는 몇 퍼센트에 불과하므로 "느린" 방법을 사용하는 것이 좋습니다.

일반적으로 쉘 스크립트의 목적은 작업을 신속하게 완료하는 것입니다. 스크립트 작성에 추가 시간을 소비하는 것을 정당화하려면 최적화를 통해 상당한 이점을 얻어야 합니다.

답변2

쉘은 수신한 코드를 재구성하지 않고 단지 한 줄씩 해석할 뿐입니다(명령 해석기에서는 다른 어떤 것도 의미가 없습니다). 쉘이 소비하는 대부분의 시간은 호출하는 프로그램을 구문 분석하고 시작하는 데 소요됩니다.

간단한 작업(질문 끝에 있는 예제의 문자열 수정과 같은)의 경우 프로그램을 로드하는 데 걸리는 시간으로 인해 작은 속도 차이가 사라지지 않는다면 놀랄 것입니다.

이야기의 교훈은 정말로 더 빠른 속도가 필요하다면 Perl이나 Python과 같은 (반)컴파일 언어를 사용하는 것이 더 낫다는 것입니다. Perl이나 Python은 시작하기 더 빠르고 직접 언급된 많은 작업을 작성할 수 있습니다. 외부 프로그램을 호출할 필요가 없으며 대부분의 작업을 수행하기 위해 외부 프로그램을 호출하거나 최적화된 C(또는 기타) 모듈을 호출하도록 선택할 수 있습니다. 이것이 Fedora에서 "시스템 관리 설탕"(본질적으로 GUI)이 Python으로 작성된 이유입니다. 멋진 GUI를 추가하는 데 많은 노력이 필요하지 않으며 이러한 종류의 응용 프로그램에 충분히 빠르며 시스템 호출에 직접 액세스할 수 있습니다. . 속도가 충분히 빠르지 않다면 C++ 또는 C를 선택하세요.

하지만원하지 않는다할 수 없으면 거기로 가세요입증하다성능 향상은 유연성과 개발 시간의 손실만큼 가치가 있습니다. 쉘 스크립트는 잘 읽히지만 Ultrix를 설치하는 데 사용된 스크립트 중 일부를 해독하려고 시도할 때 몸이 떨립니다. 포기하고 너무 많은 "쉘 스크립트 최적화"를 적용했습니다.

답변3

여기서는 위의 와일드카드 예를 확장하여 쉘 스크립트 인터프리터의 일부 성능 특성을 설명하겠습니다. 30,000개의 파일 각각에 대해 프로세스가 생성되는 이 예에서 bash및 인터프리터를 비교하면 대시 포크가 거의 빠른 속도로 처리된다는 것을 알 수 있습니다.dashwcbash

bash-4.2$ time dash -c 'for i in *; do wc -l "$i"; done>/dev/null'
real    0m1.238s
user    0m0.309s
sys     0m0.815s


bash-4.2$ time bash -c 'for i in *; do wc -l "$i"; done>/dev/null'
real    0m1.422s
user    0m0.349s
sys     0m0.940s

프로세스를 호출하지 않고 기본 루프 속도를 비교하면 wc대시 루프가 거의 6배 더 빠르다는 것을 알 수 있습니다!

$ time bash -c 'for i in *; do echo "$i">/dev/null; done'
real    0m1.715s
user    0m1.459s
sys     0m0.252s



$ time dash -c 'for i in *; do echo "$i">/dev/null; done'
real    0m0.375s
user    0m0.169s
sys     0m0.203s

앞서 설명했듯이 루프는 두 셸 모두에서 여전히 상대적으로 느리므로 확장성을 위해 컴파일 중에 반복을 수행하기 위해 더 많은 기능적 기술을 사용해야 합니다.

$ time find -type f -print0 | wc -l --files0-from=- | tail -n1
    30000 total
real    0m0.299s
user    0m0.072s
sys     0m0.221s

위의 내용은 단연 가장 효율적인 솔루션이며 요점을 잘 보여줍니다. 쉘 스크립트에서 가능한 한 적은 작업을 수행하고 이를 사용하여 UNIX 시스템의 기존 논리에서 사용할 수 있는 풍부한 유틸리티 세트에 연결하는 것을 목표로 해야 합니다.

에서 도난당함일반적인 쉘 스크립트 오류저자: Padraig Brady.

답변4

내 빠른 조치:

  • 서브셸을 사용하지 마세요.

    • (서브 쉘 없음)은 (서브 쉘) { }대신 자주/때때로 사용될 수 있다는 점을 명심하십시오 .( )
  • 쉘 내장 기능을 사용하면 외부 명령이 쉬워집니다.

    • date()/usr/bin/date예를 들어, 대신 쉘 함수를 호출하여 날짜를 얻으려면printf
  • 쉘 변수를 사용하면 쉘 내장 명령이나 명령 호출이 쉬워집니다.

    • $SECONDS예를 들어, 현재 시간을 얻으려면 을 호출하는 대신 쿼리를 사용할 수 있다면 date()전자가 더 빠릅니다.
  • 문자열 조작의 경우 변수 확장을 사용하여 외부 명령 호출( 등 ) ${...}과 같은 대안을 지원합니다 .cuttr

  • 텍스트 파일로 작업할 때 가능하면 변수를 한 줄씩 읽는 것을 피하고 대신 전체 파일에 대해 , , 등의 외부 명령을 사용 sed하십시오 tr.cut

    • 데이터 필터링(정보 축소)을 포함하여 데이터 처리를 위해 텍스트 파일을 변수로 읽어야 하는 경우 외부 명령을 사용하여 전체 파일을 필터링한 다음 필터링된(축소된) 데이터를 변수로 읽어보세요.
  • 정규 표현식을 사용하는 경우 역추적을 방지하기 위해 주의 깊게 작성하세요.

    • 잘못 작성된 정규식의 성능은 때때로 동등한 정규식보다 100배 이상 나쁠 수 있습니다.

관련 정보