400GiB가 넘는 데이터가 포함된 디렉터리가 있습니다. 모든 파일을 오류 없이 읽을 수 있는지 확인하고 싶기 때문에 제가 생각한 간단한 방법은 tar
이를 /dev/null
.
$ time tar cf /dev/null .
real 0m4.387s
user 0m3.462s
sys 0m0.185s
$ time tar cf - . > /dev/null
real 0m3.130s
user 0m3.091s
sys 0m0.035s
$ time tar cf - . | cat > /dev/null
^C
real 10m32.985s
user 0m1.942s
sys 0m33.764s
위의 세 번째 명령은 Ctrl오랜 시간 동안 실행한 후 강제로 중지되었습니다. C또한 처음 두 명령이 작동할 때 포함된 저장 장치의 활동 표시기는 .
거의 항상 유휴 상태입니다. 세 번째 명령이 실행되면 표시등이 계속 켜져 있어 매우 바쁘다는 의미입니다.
이러한 관점에서 볼 때 tar
출력 파일을 찾을 수 있을 때 /dev/null
, 즉 /dev/null
쓰기용 파일 핸들을 직접 열 때 tar
파일 본문을 건너뜁니다. ( v
옵션을 추가하면 tar
디렉터리의 모든 파일이 tar
"빨간색"으로 인쇄됩니다.)
그래서 알고 싶습니다. 왜 이런 일이 일어나는 걸까요? 일종의 최적화인가요? 그렇다면 왜 tar
이 특정 사례에 대해 그렇게 의심스러운 최적화가 이루어졌습니까?
저는 Linux 4.14.105 amd64에서 GNU tar 1.26과 glibc 2.27을 사용하고 있습니다.
답변1
그것예 기록된 최적화:
아카이브가 생성되면
/dev/null
GNU tar는 입력 및 출력 작업을 최소화하려고 시도합니다. GNU tar와 함께 Amanda 백업 시스템을 사용할 때 이 기능을 사용하는 초기 크기 조정 프로세스가 있습니다.
답변2
이는 다양한 프로그램에서 발생할 수 있습니다. 예를 들어, cp file /dev/null
사용할 때 이런 동작을 경험한 적이 있습니다. 이 명령은 디스크 읽기 속도를 예측하지 못하지만 몇 밀리초 후에 반환됩니다.
내가 기억하는 한 그것은 Solaris나 AIX에 있었지만 이 원칙은 모든 종류의 unix-y 시스템에 적용됩니다.
과거에는 프로그램이 파일을 어딘가에 복사할 때 read
디스크(또는 파일 설명자가 참조하는 모든 것)의 일부 데이터를 메모리로 가져오기 위한 호출( read
반환 시 모든 것이 거기에 있을 것임을 보장)과 write
가져오기 호출을 번갈아 가며 수행했습니다. 메모리 블록을 삭제하고 내용을 대상으로 보냅니다).
그러나 동일한 목표를 달성하는 데는 최소한 두 가지 새로운 방법이 있습니다.
Linux에는 시스템 호출
copy_file_range
(다른 UNIX에 전혀 이식 가능하지 않음) 및sendfile
(다소 이식 가능, 원래 네트워크로 파일을 전송하도록 설계되었지만 이제는 모든 대상에서 사용할 수 있음)이 있습니다. 그 목적은 전송을 최적화하는 것입니다. 프로그램이 이들 중 하나를 사용하는 경우 커널이 대상을 인식/dev/null
하고 시스템 호출을 무작동으로 바꾸는 것을 상상하기 쉽습니다.mmap
프로그램은 대신 파일 내용을 가져오는 데 사용할 수 있습니다read
. 이는 기본적으로 "시스템 호출이 반환될 때 데이터가 있는지 확인" 대신 "해당 메모리 블록에 액세스하려고 할 때 데이터가 있는지 확인"을 의미합니다. 따라서 프로그램은mmap
소스 파일을 가져온 다음write
매핑된 메모리 블록을 호출할 수 있습니다. 그러나 쓰기에는/dev/null
작성된 데이터에 대한 액세스가 필요하지 않으므로 "파일이 있는지 확인하세요" 조건이 트리거되지 않아 파일을 읽을 수도 없습니다.
gnu tar가 쓰기 작업을 감지할 때 이러한 메커니즘 중 하나를 사용하는지, 어떤 메커니즘을 사용하는지 확실하지 않지만 /dev/null
이것이 모든 프로그램의 이유입니다.읽기 속도를 확인하는 데 사용하는 경우| cat > /dev/null
, -run 대신 사용해야 합니다 > /dev/null
. 왜 | cat > /dev/null
그래야 할까요?피함다른 모든 경우에는.