파이프 라인은 메모리 사용을 어떻게 제한합니까? 더 큰 버퍼를 제공하기

Brian Kernighan 은이 비디오 에서 메모리 제한을 기반으로하는 작은 언어 / 프로그램에 대한 초기 Bell Lab의 매력을 설명합니다.

큰 기계는 64k 바이트 (K 또는 M이 아닌 G)이므로 개별 프로그램이 크지 않을 수 있으므로 작은 프로그램을 작성하는 자연스러운 경향이 있었고 파이프 메커니즘은 기본적으로 입력 출력 리디렉션을 통해 한 프로그램을 다른 프로그램에 연결할 수 있습니다.

그러나 프로그램간에 전송하기 위해 데이터를 RAM에 저장해야한다는 사실을 고려할 때 이것이 메모리 사용을 제한 할 수있는 방법을 이해하지 못합니다.

에서 위키 백과 :

대부분의 유닉스 계열 시스템에서 파이프 라인의 모든 프로세스는 동시에 시작됩니다. [강조 광산]시스템에서 실행중인 다른 모든 프로세스와 함께 스트림이 적절하게 연결되고 스케줄러에 의해 관리됩니다. 유닉스 파이프를 다른 파이프 구현과 구별하여 설정하는 중요한 측면은 버퍼링의 개념입니다. 데이터가 손실됩니다. 대신, 송신 프로그램의 출력이 버퍼에 보유됩니다. 수신 프로그램이 데이터를 읽을 준비가되면 파이프 라인의 다음 프로그램이 버퍼에서 읽습니다. Linux에서 버퍼 크기는 65536 바이트 (64KB)입니다. 필요한 경우 더 큰 버퍼를 제공하기 위해 bfr이라는 오픈 소스 타사 필터를 사용할 수 있습니다.

소규모 프로그램의 목적을 완전히 상실하기 때문에 (이것은 특정 규모까지 모듈화 될 수 있기 때문에) 이것은 나를 더 혼란스럽게합니다.

첫 번째 질문 (크기 데이터에 따라 문제가되는 메모리 제한)에 대한 해결책으로 생각할 수있는 유일한 것은 큰 데이터 세트가 단순히 계산되지 않았고 파이프 라인이 해결해야 할 실제 문제는 프로그램 자체에 필요한 메모리 양 그러나 Wikipedia 인용문에 굵은 글씨가 있으면 한 번에 하나의 프로그램이 구현되지 않기 때문에 혼란 스럽습니다.

임시 파일을 사용하면이 모든 것이 의미가 있지만 파이프가 디스크에 쓰지 않는다는 것을 이해합니다 (스왑이 사용되지 않는 한).

예:

sed 'simplesubstitution' file | sort | uniq > file2

sed파일을 읽고 한 줄씩 뱉어내는 것이 분명 합니다. 그러나 sortBK 링크 된 영상의 상태로 모든 데이터의 다음이에게 전달있어, 메모리에 읽을 수있다 (또는합니까?) 때문에, 전체 정류장이있다 uniq한 것 (내 마음을)하는, 한 번에 한 줄씩 프로그램. 그러나 첫 번째 파이프와 두 번째 파이프 사이의 모든 데이터는 메모리에 있어야합니다.



답변

데이터는 RAM에 저장 될 필요가 없습니다. 독자가 없거나 유지할 수없는 경우 파이프는 작성자를 차단합니다. 리눅스 (그리고 대부분의 다른 구현에서는 상상할 수 있음)에는 버퍼링이 있지만 필요하지는 않습니다. mtraceurJdeBP에서 언급 한대로 ( 후자의 답변 참조)), 초기 버전의 Unix 버퍼 파이프를 디스크에 저장하는 방식으로 메모리 사용을 제한하는 데 도움이되었습니다. 프로세싱 파이프 라인은 작은 프로그램으로 분할 될 수 있으며 각 프로그램은 디스크 버퍼 제한 내에서 일부 데이터를 처리 할 수 ​​있습니다. 작은 프로그램은 메모리를 덜 사용하고 파이프를 사용하면 처리를 직렬화 할 수 있습니다. 첫 번째 프로그램이 실행되고 출력 버퍼를 채우고 일시 중단 된 다음 두 번째 프로그램이 예약되고 버퍼를 처리하는 등 초기 유닉스 시스템보다 크기가 크며 많은 파이프를 병렬로 실행할 수 있습니다. 그러나 방대한 양의 데이터의 경우에도 비슷한 효과가 나타납니다 (이러한 종류의 기술은 “빅 데이터”처리에 사용됩니다).

귀하의 예에서

sed 'simplesubstitution' file | sort | uniq > file2

sedfile필요에 따라 데이터를 읽은 다음 sort읽을 준비가되어있는 한 데이터 를 씁니다 . 경우는 sort, 쓰기 블록 준비되지 않았습니다. 데이터는 결국 메모리에 실제로 라이브 않지만,의 특정 것과 sort, 그리고 sort(그것은 일종의 데이터의 양이 너무 많으면 임시 파일을 사용합니다) 어떤 문제를 처리 할 준비가되어 있습니다.

당신은 실행하여 차단 동작을 볼 수 있습니다

strace seq 1000000 -1 1 | (sleep 120; sort -n)

이렇게하면 상당한 양의 데이터가 생성 되고 처음 2 분 동안 아무것도 읽을 없는 프로세스로 파이프됩니다 . 많은 write작업이 진행되는 것을 볼 수 있지만 seq, 커널에 의해 차단 된 2 분 동안 매우 빠르게 중지되고 대기합니다 ( write시스템 호출 대기).


답변

그러나 프로그램간에 전송하기 위해 데이터를 RAM에 저장해야한다는 사실을 고려할 때 이것이 메모리 사용을 제한 할 수있는 방법을 이해하지 못합니다.

이것이 근본적인 오류입니다. 초기 버전의 Unix는 파이프 데이터를 RAM에 보관하지 않았습니다. 그들은 그것들을 디스크에 저장했습니다. 파이프에는 i- 노드가있었습니다. 파이프 장치 로 표시된 디스크 장치에서 . 시스템 관리자는 /etc/config어떤 디스크에서 어떤 파이프가 파이프 장치 였는지, 어떤 볼륨이 루트 장치인지 , 어떤 덤프 장치 인지 지정하기 위해 명명 된 프로그램을 실행했습니다 .

보류중인 데이터의 양은 디스크에서 i- 노드 의 직접 블록 만 저장에 사용 되었다는 사실에 의해 제약되었습니다 . 이 메커니즘은 코드를 더 단순하게 만들었습니다. 파이프에서 읽을 수없고 버퍼가 원형이라는 사실로 인해 약간의 조정으로 인해 일반 파일을 읽는 데 사용되는 것과 동일한 알고리즘이 파이프에서 읽기에 사용 되었기 때문입니다.

이 메커니즘은 1980 년대 중반에서 후반에 다른 것으로 대체되었습니다. SCO XENIX는 i- 노드를 인 코어 버퍼로 대체 한 “고성능 파이프 시스템”을 확보했습니다. 4BSD는 명명되지 않은 파이프를 소켓 쌍으로 만들었습니다. STREAMS 메커니즘을 사용하여 AT & T 파이프를 재 구현했습니다.

물론 sort프로그램은 제한된 내부 정렬의 32KiB 청크 (또는 32KiB를 사용할 수없는 경우 할당 할 수있는 더 적은 양의 메모리)를 수행하여 정렬 된 결과를 중간 stmX??파일에 /usr/tmp/기록한 다음 외부 병합하여 최종 정렬을 제공합니다. 산출.

추가 자료

  • 스티브 디 페이트 (1996). “프로세스 간 통신”. 유닉스 내부 : 실용적 접근 . 애디슨 웨슬리 ISBN 9780201877212.
  • 모리스 제이 바흐 (1987). “파일 시스템을위한 시스템 호출”. 유닉스 운영 체제의 디자인 . 프렌 티스 홀. ISBN 0132017571.
  • Steven V. Earhart (1986). ” config(1M)”입니다. 유닉스 프로그래머 매뉴얼 : 3. 시스템 관리 기능 . 홀트, 라인 하트, 윈스턴 ISBN 0030093139. 23-28 쪽.

답변

부분적으로 정확하지만 실수 로만 가능 합니다 .

귀하의 예에서, 모든 데이터는 실제로 파이프 사이에 읽혀 져야하지만 메모리 (가상 메모리 포함)에 상주 할 필요는 없습니다. 일반적인 구현은 sort임시 파일에 부분 정렬을 수행하고 병합하여 RAM에 맞지 않는 데이터 세트를 정렬 할 수 있습니다. 그러나 각 요소를 모두 읽기 전에 정렬 된 시퀀스를 출력 할 수는 없습니다. 꽤 분명합니다. 그렇습니다 sort. 처음부터 모든 것을 읽은 후 (그리고 부분적으로 정렬 된 임시 파일을 수행 한 후에) 두 번째 파이프로 출력을 시작할 수 있습니다. 그러나 반드시 모든 것을 RAM에 보관할 필요 는 없습니다 .

그러나 이것은 파이프의 작동 방식과 관련이 없습니다. 파이프는 이름이 지정 될 수 있으며 (전통적으로 모두 이름이 지정됨) 파일과 같이 파일 시스템에 파일 위치가 있다는 것 이상의 의미는 없습니다. 그리고 그것은 한때 파이프가 있던 파일입니다. (물리적 메모리 가용성이 허용하는 한 쓰기가 최적화로 합쳐졌습니다).

요즘 파이프는 데이터가 복사되는 작고 유한 한 크기의 커널 버퍼 입니다. 최소한 그것이 개념적으로 일어나는 것입니다. 커널이 도움을 줄 수있는 경우 VM 트릭을 재생하여 사본을 제거합니다 (예를 들어 파일에서 파이핑하면 일반적으로 다른 프로세스에서 동일한 페이지를 읽을 수있게되므로 결국 두 사본이 아니라 읽기 작업 만 수행함) 어쨌든 버퍼 캐시에서 이미 사용했던 것보다 추가 메모리가 필요합니다. 어떤 상황에서는 100 % 제로 복사를 얻을 수 있습니다.

파이프가 작고 유한 한 크기 인 경우 알려지지 않은 (아마도 많은) 양의 데이터에 대해 어떻게 작동합니까? 간단합니다. 더 이상 적합한 것이 없으면 다시 공간이 생길 때까지 쓰기가 차단됩니다.

많은 간단한 프로그램의 철학은 기억력이 매우 부족한 시대에 가장 유용했습니다. 한 번에 하나씩 작은 단계로 작업을 수행 할 수 있기 때문입니다. 요즘, 장점은 추가 유연성을 제외하고는 더 이상 대단하지 않습니다.
그러나 파이프는 매우 효율적으로 구현되므로 (그렇습니다!) 단점도 없으며, 잘 작동하고 사람들에게 익숙한 확립 된 것이므로 패러다임을 바꿀 필요가 없습니다.


답변