새로운 빈 파일을 작성하는 것보다 기존 파일에 쓰는 것이 더 빠른 이유는 무엇입니까?

새로운 빈 파일을 작성하는 것보다 기존 파일에 쓰는 것이 더 빠른 이유는 무엇입니까?

Linux에서 파일을 작성하기 위해 MappedByteBuffer를 사용하고 있습니다.

File file = new File("testFile");
RandomAccessFile raf = new RandomAccessFile(file, "rw");
FileChannel fc = raf.getChannel();
MappedByteBuffer mbf = fc.map(FileChannel.MapMode.READ_WRITE, 0, file.length());
mbf.put(buffer);

testFile에 500MB를 쓰고 500MB 데이터를 두 번 쓰면 1초가 걸립니다. 하지만 testFile을 실행하면 500MB 데이터를 쓰는 데 4초가 걸립니다.

새 파일을 쓰는 것보다 파일을 덮어쓰는 것이 더 빠른 이유는 무엇입니까? 파일을 덮어쓰는 것처럼 새 파일을 더 빨리 쓰려면 어떻게 해야 합니까?

답변1

덮어쓰는 것이 더 빠른지 아니면 새 파일을 만드는 것이 더 빠른지는 파일 시스템 유형에 따라 다릅니다. 많은 파일 시스템은 파일 데이터를 제자리에서 덮어쓰기만 하면 되므로 덮어쓰기가 더 빠른 반면, 새 파일을 생성하려면 먼저 공간을 할당한 다음 새로 할당된 공간에 데이터를 써야 합니다. 하지만 큰 차이는 없을 것으로 예상됩니다. 일부 파일 시스템은 기존 블록을 덮어쓰지 않습니다.취소하려면 쓰기) 그런 다음 새 데이터를 쓰고 이전 데이터를 삭제하여 기존 파일을 덮어씁니다. 그러나 나는 두 상황 사이에 큰 차이가 없다고 생각합니다.

기본 레이어도 비슷한 효과를 가져서 한 작업을 다른 작업보다 비용이 더 많이 들 수 있습니다. 예를 들어, 스냅샷이 저장된 시스템을 덮어쓰면 스냅샷을 복원할 수 있도록 이전 데이터가 보존됩니다. 플래시 미디어는 일괄적으로만 지울 수 있기 때문에 비어 있는 섹터에 새 데이터가 기록되지만, 일부 데이터를 덮어쓰면 결국 해제되므로 시간이 걸립니다.

읽기 및 쓰기 타이밍에 가장 큰 영향을 미치는 것은 버퍼링과 캐싱입니다. sync핫 캐시/버퍼 타이밍을 측정하려는 경우를 제외하고 알려진 캐시 구성에서 벤치마킹하고(각 벤치마크 작업을 시작하기 전에 디스크 캐시를 플러시해야 함) 모든 쓰기에 대한 버퍼로 끝나야 합니다( 를 호출하여 수행됨 ). 예를 들어 두 번의 연속 쓰기(첫 번째 쓰기는 메모리 버퍼에만 쓰기)를 수행하면 단일 쓰기를 수행하는 것보다 비용이 더 많이 들지 않습니다.

어쨌든, 원하는 일을 하는 데 4초가 걸린다면, 4초가 걸리는 것입니다. 4배 빠르게 만드는 마법 같은 방법은 없습니다.

답변2

이를 사용한 빠른 테스트는 dd파일에 데이터를 추가하는 것이 더 빠르지 않다는 것을 보여줍니다.

내 테스트 파일 크기는 1024MB입니다. 최종 첨부파일 크기는 2048MB입니다.

creating a new file
real    0m3,052s
user    0m0,523s
sys     0m0,578s

overwriting existing file
real    0m3,510s
user    0m0,695s
sys     0m0,867s

appending to existing file
real    0m3,226s
user    0m0,602s
sys     0m0,594s

deleting file
real    0m0,273s
user    0m0,086s
sys     0m0,195s

테스트.sh:

#!/usr/bin/env bash
printf "creating a new file\n"
time dd if=/dev/zero of=./test.img count=1024 bs=1M && sync -f

printf "\noverwriting existing file\n"
time dd if=/dev/zero of=./test.img count=1024 bs=1M && sync -f

printf "\nappending to existing file\n"
time dd if=/dev/zero bs=1M count=1024 >> ./test.img && sync -f

printf "\ndeleting file\n"
[[ -f ./test.img ]] && time rm ./test.img && sync -f

관련 정보