고양이는 게으른 평가를 사용합니까?

고양이는 게으른 평가를 사용합니까?

예를 들어 파이프를 사용할 때

sudo cat /dev/sda | strings | less

내 SDA 장치의 문자열 라인을 따라 이동할 수 있습니다. 그런데 sda 장치의 내용이 완전히 로드되어 cat의 출력 스트림으로 출력됩니까? 아니면 프로그램이 cat 의 출력을 요청할 때마다 새 줄이 평가됩니까? (즉, 적은 호출기에서 j를 누릅니다)

답변1

less이는 어떻게 작동하는지보다는 어떻게 작동하는지 cat와 더 관련이 있습니다 strings.

이 명령은 데이터를 표준 출력으로만 푸시하며, 그 사이의 파이프 버퍼가 가득 차서 아무도 읽지 않을 cat때마다 차단됩니다 . 자체적으로 최소한의 버퍼링을 수행하며 파이프 버퍼는 일반적으로 작습니다.stringscat

이는 에도 해당됩니다 strings. 생성 된 데이터를 읽지 않을 때 데이터를 처리 cat하고 차단합니다 .lessstrings

less표시되는 데이터에서 앞뒤로 이동할 수 있도록 입력을 버퍼링합니다. 다음 페이지로 스크롤하면 은(는) 해당 버퍼 less에서 더 많은 데이터를 읽습니다 strings. 앞으로 스크롤하지 않는 동안에는 제한된 양의 데이터만 읽을 것이라고 믿습니다 less. 따라서 앞으로 스크롤하지 않는 동안에는 차단됩니다 strings.cat

많은 양의 데이터를 에 파이프하면 less이 버퍼링에 꽤 많은 메모리가 사용됩니다.만약에당신은 그것을 끝까지 읽기로 결정했습니다 less.

-B버퍼링에 사용되는 메모리 양을 64KB(또는 옵션으로 지정한 양 -b) 로 제한하는 옵션이 있습니다 . 이러한 방식으로 버퍼 크기를 제한하면 지정된 버퍼 공간에 저장할 수 있는 것보다 더 많이 뒤로 스크롤하는 것을 방지할 수 있을 뿐만 아니라 less메모리 부족 없이 엄청난 양의 데이터를 읽을 수 있습니다 .

man less시스템에서도 참조하세요 .

답변2

파이프에는 버퍼 공간이 제한되어 있으며 파이프 판독기(예: less예제)가 파이프에서 더 많은 데이터를 읽지 않으면 버퍼를 채운 후 기록기가 차단됩니다. 이는 명령에 영향을 미치며 파이프가 가득 찬 후에 strings는 명령을 차단합니다 .cat

당연히 이 cat명령은 전체 sda 장치 내용을 주 메모리로 읽을 수 없으므로 아직 읽지 않은 블록이 변경되는 경우 cat변경된 내용을 볼 수 있습니다.

답변3

cat및 대부분 strings의 유사한 유틸리티1는 한 번에 조금씩 입력을 읽고 처리한 다음 더 많은 입력을 읽는 등의 작업을 수행합니다. 따라서 귀하의 경우에는 표시되는 내용과 전송 중인 내용 cat만 읽습니다 .less

더 자세히 살펴보면 기본 동작은 cat다음과 같습니다.

  • 버퍼로 사용하기 위해 몇 킬로바이트의 메모리를 예약합니다.
  • 더 많은 입력이 가능하지만:
    • 버퍼에 최대 N바이트의 입력을 읽습니다. (이전 사이클에서 기록된 데이터를 덮어씁니다.)
    • 버퍼 내용을 출력에 씁니다.

출력을 복사할 위치가 있을 때까지 쓰기 작업이 차단됩니다. 파이프의 출력 시 파이프 자체는 커널에서 약간의 메모리를 소비합니다.파이프 버퍼. 파이프가 가득 차면 cat파이프에 쓰기를 시도하면 공간이 생길 때까지 쓰기 시도가 차단됩니다. 파이프의 읽기 측 프로세스가 일부 데이터를 읽을 때 파이프 버퍼에 공간이 있을 수 있습니다.

프로그램 은 전체 입력을 복사하지 않고 선택한 부분만 복사한다는 점을 제외하면 strings와 동일한 방식으로 작동합니다 .cat

프로그램은 less약간 다르게 작동합니다. 즉, 읽은 모든 내용을 메모리에 유지합니다. 버퍼를 재활용하지 않으며 더 많은 입력이 계속 들어오는 한 계속해서 증가합니다. 그러나 읽기 부분은 less필요할 때만 데이터를 읽는다는 점에서 비슷합니다. 표시되는 마지막 줄까지만 읽습니다. , 그리고 가능한 경우 예상대로 읽는 내용을 조금 더 추가합니다.

따라서 를 실행하면 sudo cat /dev/sda | strings | less읽은 내용은 다음과 /dev/sda같이 구성됩니다.

  • less이미 표시된(또는 스크롤한) 데이터입니다 .
  • less읽었지만 아직 표시되지 않은 최대 몇 kB의 데이터입니다 .
  • strings와 사이의 파이프 버퍼에서 최대 몇 kB까지 가능합니다 less.
  • 의 메모리에는 최대 몇 kB가 있습니다 strings.
  • cat와 사이의 파이프 버퍼에서 최대 몇 kB까지 가능합니다 strings.
  • 의 메모리에는 최대 몇 kB가 있습니다 cat.

시스템 호출을 추적하여 각 프로그램이 데이터를 읽고 쓰는 시기를 확인할 수 있습니다.

sudo strace -e read,write -o cat.strace cat /dev/sda | strace -e read,write -o cat.strace strings | strace -e read,write -o less.strace less

그리고 *.strace파일을 보세요. 예를 들어 프로세스 ID가 어디에 있는지 와 같이 cat파일 오프셋을 확인하여 읽은 양을 확인할 수도 있습니다 .lsof -p1234head /proc/1234/fdinfo/01234cat

¹ 기본 텍스트 처리 유틸리티 중 주요 예외는 sort전체 입력을 읽을 때까지 출력을 내보낼 수 없는 입니다. 알고 있는 바에 따르면 출력의 첫 번째 줄은 도달하는 입력의 마지막 줄일 수 있습니다.

답변4

일부 시스템(예: MS-Dos)에서는 첫 번째 명령의 출력을 파일에 복사한 다음 두 번째 명령을 실행하여 이 파일에서 읽는 방식으로 파이프가 구현됩니다. 유닉스는 그런 식으로 하지 않는다.

Unix에서는 생산 라인과 같습니다. 각 단계는 동시에 작동하여 입력을 읽고 출력을 생성합니다. 프로세스 A가 프로세스 B가 소비하는 것보다 빠르게 생산하는 경우 프로세스 A와 B 사이에 재고가 축적됩니다. 이것이 너무 많으면(½KiB ~ 4KiB) 프로세스 A가 일시 중지됩니다. B가 처리할 재고가 없으면 B가 일시 중지됩니다. 재고 수준을 낮게 유지하기 위해 프로세스가 일시 중지되거나 일시 중지 해제됩니다.

이 프로그램의 코드는 이에 대해 전혀 신경 쓰지 않습니다. 단지 입력을 읽고 출력을 씁니다. 데이터를 사용할 수 있기 전에 읽기를 시도하거나 다음 프로세스가 준비되기 전에 쓰기를 시도하면 운영 체제는 준비될 때까지 이를 일시 중지합니다.

더 이상 읽을 내용이 없으면(그리고 더 이상 읽을 내용도 없으면) 판독기는 파일 끝(EOF)을 받고 종료됩니다. 그러면 다음 프로세스에서 파일 끝이 트리거됩니다.

관련 정보