파이프 라인은 메모리 사용을 어떻게 제한합니까?


36

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

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

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

에서 위키 백과 :

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

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

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

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

예:

sed 'simplesubstitution' file | sort | uniq > file2

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


1
unless swap is used스왑은 RAM이 충분하지 않을 때 항상 사용됩니다
edc65

답변:


44

데이터는 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시스템 호출 대기).


13
프로그램을 실행하여 메모리에 맞게 할 수 있도록했지만, 단지이 대답은 추가로 많은 작은 것들로 분할 프로그램 메모리 사용을 절약 할 이유의 설명 혜택을 누릴 수있는 현재 실행중인 프로그램. 다른 모든 프로그램은 초기 Unix에서 디스크로 스왑되었고 한 번에 하나의 프로그램 만 실제 RAM으로 스왑되었습니다. 따라서 CPU는 하나의 프로그램을 실행하여 파이프에 쓰고 (이전에는 디스크에 있음 ) 해당 프로그램을 스왑하고 파이프에서 읽은 프로그램을 스왑합니다. 논리적으로 평행 한 조립 라인을 증분 직렬화 실행으로 전환하는 우아한 방법.
mtraceur

6
@malan : 여러 프로세스를 시작하고 동시에 실행 가능한 상태에있을 수 있습니다. 그러나 주어진 시간에 각 물리적 CPU에서 최대 하나의 프로세스를 실행할 수 있으며 실행 가능한 프로세스마다 CPU 시간의 "슬라이스"를 할당하는 것이 커널 프로세스 스케줄러의 작업입니다. 현대 시스템에서 실행 가능하지만 현재 예약되지 않은 CPU 타임 슬라이스 프로세스는 일반적으로 다음 슬라이스를 기다리는 동안 메모리에 상주하지만 커널은 프로세스의 메모리를 디스크로 페이징하고 다시 메모리로 다시 보낼 수 있습니다. 편리합니다. (자세한 내용은 여기를 참고하십시오.)
Daniel Pryden

5
파이프의 양쪽에있는 프로세스는 코 루틴처럼 효과적으로 작동 할 수 있습니다. 한쪽은 버퍼와 쓰기 블록을 채울 때까지 쓰며,이 시점에서 프로세스는 나머지 타임 슬라이스로 아무 것도 할 수 없습니다. IO 대기 모드 그런 다음 OS는 나머지 타임 슬라이스 (또는 다른 다가오는 타임 슬라이스)를 읽기 측에 제공합니다. 버퍼는 버퍼에 남은 것이 없을 때까지 읽은 다음 다음 읽기 블록에서 리더 프로세스가 나머지 부분으로는 아무것도 할 수 없습니다. 그것의 타임 슬라이스와 OS로 돌아갑니다. 데이터는 한 번에 하나의 버퍼만큼 파이프를 통과합니다.
Daniel Pryden

6
@malan 프로그램은 모든 유닉스 시스템에서 개념적 으로 "동시에"시작됩니다. RAM을 보유한 RAM이 많은 최신 멀티 프로세서 시스템에서만 가능합니다. 즉, 동시에 동시에 RAM에 모두 보유 할 수있는 시스템을 의미합니다. 동시에 RAM에 모두 넣지 마십시오. 일부는 디스크로 스왑됩니다. 또한 많은 컨텍스트에서 "메모리"는 디스크의 RAM 공간과 스왑 공간의 합인 가상 메모리 를 의미 합니다. Wikipedia는 구현 세부 사항보다는 개념에 초점을 맞추고 있습니다. 특히 Unix가 실제로 얼마나 오래했는지는 덜 중요하기 때문입니다.
mtraceur 2016 년

2
@malan 또한, 모순은 "메모리"(RAM과 RAM + 스왑)의 두 가지 의미에서 비롯됩니다. 나는 하드웨어 RAM에 대해서만 이야기하고 있었고, 그 맥락에서 CPU에 의해 현재 실행중인 코드 만 RAM에 적합해야하며 (Kernighan이 결정한 결정에 영향을 미쳤습니다) 모든 프로그램의 맥락에서 논리적으로 실행됩니다 주어진 시간에 (슬라이스 상단에 제공된 추상 수준에서) OS에 의해 프로그램은 디스크의 스왑 공간을 포함하여 OS에 사용 가능한 전체 가상 메모리에 맞기 만하면됩니다.
mtraceur 2016 년

34

그러나 프로그램간에 전송하기 위해 데이터를 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 쪽.

1

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

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

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

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

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

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


'파이프 이름이 지정되었습니다'(JdeBP는 '파이프 장치' 가 하나 있다고 말한 것 같습니다)라고 말하면 주어진 시간에 사용할 수있는 파이프 수에 제한이 있음을 의미합니다 (즉, |명령에 몇 번이나 사용할 수 있습니까?
malan

2
나는 그런 한계를 본 적이 없으며 이론 상으로는 한계가 있다고 생각하지 않습니다 . 실제로 파일 이름이있는 것은 inode가 필요하고 inode의 수는 물론 유한합니다. 시스템의 실제 페이지 수와 마찬가지로 다른 것도 없습니다. 최신 시스템은 4k 아토믹 쓰기를 보장하므로 각 파이프 최소한 하나의 완전한 4k 페이지를 소유 해야 하므로 가능한 파이프 수를 제한 할 수 있습니다. 그러나 몇 기가 바이트의 RAM을 고려하십시오 ... 실제로, 그것은 결코 겪을 수없는 한계입니다. 터미널에 몇 백만 개의 파이프를 입력 해보십시오 ... :)
Damon
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.