여기에서 파이프와 문자열을 사용한 리소스 사용량

여기에서 파이프와 문자열을 사용한 리소스 사용량

다음 두 가지를 사용하여 동일한 결과를 얻을 수 있습니다 bash.

echo 'foo' | cat

그리고

cat <<< 'foo'

제 질문은 사용된 리소스 측면에서 이 둘의 차이점은 무엇이며 어느 것이 더 나은가요?입니다.

내 생각은 파이프를 사용할 때 추가 프로세스 echo와 파이프를 사용하는 반면 여기서 문자열은 파일 설명자만 사용한다는 것입니다 cat.

답변1

파이프는 커널 파일 시스템에서 열린 파일로 디스크에서 일반 파일로 접근할 수 없다. 특정 크기까지만 자동으로 버퍼링되며 가득 차면 결국 차단됩니다. 블록 장치에서 생성된 파일과 달리 파이프는 문자 장치와 매우 유사하게 동작하므로 일반적으로 지원되지 않습니다.lseek()그리고 그로부터 읽은 데이터는 일반 파일처럼 다시 읽을 수 없습니다.

여기에 있는 문자열은 마운트된 파일 시스템에 생성된 일반 파일입니다. 쉘은 파일을 생성하고 해당 설명자를 유지하는 동시에 고유한 파일 시스템 링크를 즉시 제거합니다.(그래서 삭제)파일에 바이트를 쓰거나 읽기 전에. 커널은 파일에 대한 모든 설명자가 모든 프로세스에 의해 해제될 때까지 파일에 필요한 공간을 유지합니다. 그러한 설명자를 읽는 어린이가 그렇게 할 수 있는 경우 다음을 사용하여 되돌릴 수 있습니다.lseek()그리고 다시 읽어보세요.

두 경우 모두 태그 <<<와 태그는 |파일 설명자를 나타내지만 반드시 파일 자체를 나타내는 것은 아닙니다. 다음을 수행하면 무슨 일이 일어나고 있는지 더 잘 알 수 있습니다.

readlink /dev/fd/1 | cat

...또는...

ls -l <<<'' /dev/fd/*

두 파일 사이의 가장 중요한 차이점은 here-string/doc가 거의 일회성 이벤트라는 것입니다. 즉, 쉘은 읽기 설명자를 제공하기 전에 하위 파일에 모든 데이터를 씁니다. 반면에 셸은 적절한 설명자에서 파이프를 열고 파이프 설명자를 관리하기 위해 하위 프로세스를 포크하여 작성/읽기됩니다.동시에양쪽 끝에서.

그러나 이러한 차이점은 단지일반적으로 말하면진짜. 내가 아는 한(실제로는 그리 멀지 않음)이는 한 가지 예외를 제외하고 여기에서 문서 리디렉션의 문자열 약어를 처리하는 <<<거의 모든 쉘에 해당됩니다.<<yash. 그러나 yash, busybox, dash, 및 기타 ash변형은 여기에 설명된 대로 파이프 사용을 지원하는 경향이 있으므로 이러한 셸에서는 실제로 둘 사이에 차이가 없습니다.

좋습니다. 두 가지 예외가 있습니다. 지금 생각해 보면 실제로는 파이프 작업을 전혀 수행하지 않고 소켓을 사용하여 전체 비즈니스를 처리합니다. 비록 ksh93대부분의 다른 사람들처럼 |임시 파일을 삭제하지만 말입니다. <<<*더 중요한 것은 파이프라인의 다양한 부분을 하나로 통합한다는 것입니다.서브쉘 환경이것은 POSIX에 대한 완곡한 표현입니다.적어도 서브쉘처럼 작동합니다., 그러니 포크도 만들지 마세요.

사실이 벤치마크입니다 @PSkocik(이것은 매우 유용합니다)여기의 결과는 크게 다를 수 있습니다많은이유는 대부분 구현과 관련되어 있습니다. 여기서 문서 설정의 가장 큰 요소는 대상 ${TMPDIR}파일 시스템 유형과 현재 캐시 구성/가용성, 그리고 기록할 데이터의 양입니다. 파이프의 경우 필요한 포크에 대해 복사본이 만들어지기 때문에 쉘 프로세스 자체의 크기가 됩니다. 그게 bash다야나쁜파이프라인 설정 중( $(명령 )대체 포함)- 규모가 크기 때문에매우느리지만 사용해 ksh93도 거의 차이가 없습니다.

다음은 쉘이 파이프용 하위 쉘을 분할하는 방법을 보여주는 또 다른 작은 쉘 조각입니다.

pipe_who(){ echo "$$"; sh -c 'echo "$PPID"'; }
pipe_who
pipe_who | { pipe_who | cat /dev/fd/3 -; } 3<&0

32059  #bash's pid
32059  #sh's ppid
32059  #1st subshell's $$
32111  #1st subshell sh's ppid
32059  #2cd subshell's $$
32114  #2cd subshell sh's ppid

pipe_who()파이프라인 호출로 보고된 내용과 현재 셸에서 실행 중인 보고서의 차이점은 (확장 시 )상위 셸의 pid를 선언하는 하위 셸의 지정된 동작 때문입니다. 서브쉘은 확실히 별도의 프로세스이지만 $$특수 쉘 매개변수는 이 정보의 신뢰할 수 있는 소스가 아닙니다. 그럼에도 불구하고, 서브쉘의 서브쉘은 자신의 .bash$$sh$PPID

답변2

벤치마킹을 대체할 수 있는 것은 없습니다.

pskocik@ProBook:~ 
$ time (for((i=0;i<1000;i++)); do cat<<< foo >/dev/null; done  )

real    0m2.080s
user    0m0.738s
sys 0m1.439s
pskocik@ProBook:~ 
$ time (for((i=0;i<1000;i++)); do echo foo |cat >/dev/null; done  )

real    0m4.432s
user    0m2.095s
sys 0m3.927s
$ time (for((i=0;i<1000;i++)); do cat <(echo foo) >/dev/null; done  )
real    0m3.380s
user    0m1.121s
sys 0m3.423s

대용량 데이터의 경우:

TENMEG=$(ruby -e 'puts "A"*(10*1024*1024)')
pskocik@ProBook:~ 
$ time (for((i=0;i<100;i++)); do echo "$TENMEG" |cat >/dev/null; done  )

real    0m42.327s
user    0m38.591s
sys 0m4.226s
pskocik@ProBook:~ 
$ time (for((i=0;i<100;i++)); do cat<<< "$TENMEG" >/dev/null; done  )

real    1m26.946s
user    1m23.116s
sys 0m3.681s
pskocik@ProBook:~ 

$ time (for((i=0;i<100;i++)); do cat <(echo "$TENMEG") >/dev/null; done  )

real    0m43.910s
user    0m40.178s
sys 0m4.119s

덕트 버전은 설치 비용이 더 많이 드는 것처럼 보이지만 궁극적으로 더 효율적입니다.

답변3

당신이 알아차렸듯이,관로하위 프로세스를 생성하고여기에 있는 문자열확실히. 이는 어떤 경우에는 중요할 수 있습니다.

다음을 비교해보세요:

하지만:

grep $USER /etc/passwd | IFS=: read user x1 uid gid x2 home shell 
echo $user $uid $gid

아무것도 표시하지 않습니다.

IFS=: read user x1 uid gid x2 home shell <<<$(grep $USER /etc/passwd)
echo $user $uid $gid

보여주다:

myuser 1000 1000

관련 정보