C ++로 바이너리 파일 작성하기


241

SSD (솔리드 스테이트 드라이브)에 방대한 양의 데이터를 쓰려고합니다. 그리고 엄청난 양의 80GB를 의미합니다.

솔루션을 웹에서 탐색했지만 가장 좋은 방법은 다음과 같습니다.

#include <fstream>
const unsigned long long size = 64ULL*1024ULL*1024ULL;
unsigned long long a[size];
int main()
{
    std::fstream myfile;
    myfile = std::fstream("file.binary", std::ios::out | std::ios::binary);
    //Here would be some error handling
    for(int i = 0; i < 32; ++i){
        //Some calculations to fill a[]
        myfile.write((char*)&a,size*sizeof(unsigned long long));
    }
    myfile.close();
}

Visual Studio 2010 및 전체 최적화로 컴파일되고 Windows7에서 실행되는이 프로그램은 최대 약 20MB / s입니다. 정말 귀찮은 점은 Windows가 150MB / s와 200MB / s 사이의 다른 SSD 에서이 SSD로 파일을 복사 할 수 있다는 것입니다. 따라서 7 배 이상 빠릅니다. 그래서 더 빨리 갈 수 있어야한다고 생각합니다.

글쓰기 속도를 높이는 방법에 대한 아이디어가 있습니까?


11
타이밍 결과에 a []를 채우기 위해 계산을 수행하는 데 걸리는 시간이 제외 되었습니까?
catchmeifyoutry

7
나는 실제로이 작업을 전에 수행했습니다. 간단한 fwrite()것을 사용하면 최대 쓰기 속도의 약 80 %를 얻을 수 있습니다. 오직 FILE_FLAG_NO_BUFFERING최대 속도를 얻을 수있었습니다.
신비주의

10
파일 쓰기를 SSD-to-SSD 복사와 비교하는 것이 불공평합니다. SSD-to-SSD는 C ++ 라이브러리를 피하거나 DMA (direct memory access)를 사용하여 하위 수준에서 작동 할 수 있습니다. 무언가를 복사하는 것은 임의의 값을 랜덤 액세스 파일에 쓰는 것과 다릅니다.
Igor F.

4
@ IgorF .: 그것은 단지 잘못된 추측입니다. 그것은 완벽하게 공정한 비교입니다 (파일 작성을 선호하는 다른 것이 없다면). Windows에서 드라이브를 통한 복사는 읽기 및 쓰기입니다. 화려하고 복잡하거나 다른 것은 없습니다.
user541686

5
@MaximYegorushkin : 링크 또는 발생하지 않았습니다. : P
541686

답변:


233

이것은 2012 년에 일을했습니다 :

#include <stdio.h>
const unsigned long long size = 8ULL*1024ULL*1024ULL;
unsigned long long a[size];

int main()
{
    FILE* pFile;
    pFile = fopen("file.binary", "wb");
    for (unsigned long long j = 0; j < 1024; ++j){
        //Some calculations to fill a[]
        fwrite(a, 1, size*sizeof(unsigned long long), pFile);
    }
    fclose(pFile);
    return 0;
}

36 초 만에 8GB의 시간을 가졌습니다. 약 220MB / s이며 SSD를 최대한 활용한다고 생각합니다. 또한 문제의 코드는 하나의 핵심 100 %를 사용했지만이 코드는 2-5 % 만 사용합니다.

모두에게 감사합니다.

업데이트 : 5 년이 지난 지금 2017 년이 지났습니다. 컴파일러, 하드웨어, 라이브러리 및 요구 사항이 변경되었습니다. 그래서 코드를 약간 변경하고 새로운 측정을 수행했습니다.

먼저 코드를 작성하십시오.

#include <fstream>
#include <chrono>
#include <vector>
#include <cstdint>
#include <numeric>
#include <random>
#include <algorithm>
#include <iostream>
#include <cassert>

std::vector<uint64_t> GenerateData(std::size_t bytes)
{
    assert(bytes % sizeof(uint64_t) == 0);
    std::vector<uint64_t> data(bytes / sizeof(uint64_t));
    std::iota(data.begin(), data.end(), 0);
    std::shuffle(data.begin(), data.end(), std::mt19937{ std::random_device{}() });
    return data;
}

long long option_1(std::size_t bytes)
{
    std::vector<uint64_t> data = GenerateData(bytes);

    auto startTime = std::chrono::high_resolution_clock::now();
    auto myfile = std::fstream("file.binary", std::ios::out | std::ios::binary);
    myfile.write((char*)&data[0], bytes);
    myfile.close();
    auto endTime = std::chrono::high_resolution_clock::now();

    return std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count();
}

long long option_2(std::size_t bytes)
{
    std::vector<uint64_t> data = GenerateData(bytes);

    auto startTime = std::chrono::high_resolution_clock::now();
    FILE* file = fopen("file.binary", "wb");
    fwrite(&data[0], 1, bytes, file);
    fclose(file);
    auto endTime = std::chrono::high_resolution_clock::now();

    return std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count();
}

long long option_3(std::size_t bytes)
{
    std::vector<uint64_t> data = GenerateData(bytes);

    std::ios_base::sync_with_stdio(false);
    auto startTime = std::chrono::high_resolution_clock::now();
    auto myfile = std::fstream("file.binary", std::ios::out | std::ios::binary);
    myfile.write((char*)&data[0], bytes);
    myfile.close();
    auto endTime = std::chrono::high_resolution_clock::now();

    return std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime).count();
}

int main()
{
    const std::size_t kB = 1024;
    const std::size_t MB = 1024 * kB;
    const std::size_t GB = 1024 * MB;

    for (std::size_t size = 1 * MB; size <= 4 * GB; size *= 2) std::cout << "option1, " << size / MB << "MB: " << option_1(size) << "ms" << std::endl;
    for (std::size_t size = 1 * MB; size <= 4 * GB; size *= 2) std::cout << "option2, " << size / MB << "MB: " << option_2(size) << "ms" << std::endl;
    for (std::size_t size = 1 * MB; size <= 4 * GB; size *= 2) std::cout << "option3, " << size / MB << "MB: " << option_3(size) << "ms" << std::endl;

    return 0;
}

이 코드는 Visual Studio 2017 및 g ++ 7.2.0 (새로운 요구 사항)으로 컴파일됩니다. 두 가지 설정으로 코드를 실행했습니다.

  • 노트북, Core i7, SSD, Ubuntu 16.04, -std = c ++ 11이있는 g ++ 버전 7.2.0 -march = native -O3
  • / Ox / Ob2 / Oi / Ot / GT / GL / Gy가 포함 된 데스크톱, Core i7, SSD, Windows 10, Visual Studio 2017 버전 15.3.1

다음과 같은 측정 결과를 얻었습니다 (1MB의 값을 버린 후에는 명백한 이상치이므로) : option1과 option3 모두 SSD를 최대로 사용합니다. option2는 이전 컴퓨터에서 가장 빠른 코드 였기 때문에 이것을 보지 못했습니다.여기에 이미지 설명을 입력하십시오 여기에 이미지 설명을 입력하십시오

TL; DR : 내 측정 값이 std::fstream초과 사용 된 것으로 나타납니다 FILE.


8
+1 네, 이것이 제가 처음 시도한 것입니다. FILE*스트림보다 빠릅니다. 어쨌든 I / O에 바인딩되어 있어야했기 때문에 그러한 차이를 예상하지 못했습니다.
신비주의

12
C 스타일 I / O가 C ++ 스트림보다 (이상하게) 훨씬 빠르다는 결론을 내릴 수 있습니까?
SChepurin

21
@ SChepurin : 당신이 pedantic되고 있다면 아마 아닐 것입니다. 실용적이라면 아마 그렇습니다. :)
user541686

10
두 접근법의 차이점과 이것이 왜 원래보다 훨씬 빨리 작동하는지 설명해 주시겠습니까?
Mike Chamberlain

11
앞에 추가 ios::sync_with_stdio(false);하면 스트림이있는 코드가 달라 집니까? 나는이 줄을 사용하는 것의 차이점이 얼마나 큰지 궁금하지만 코너 케이스를 확인하기에 충분한 디스크가 없습니다. 그리고 실제 차이가 있다면.
Artur Czajka

24

다음을 순서대로 시도하십시오.

  • 더 작은 버퍼 크기. 한 번에 ~ 2 MiB를 쓰는 것이 좋습니다. 마지막 랩톱에서 ~ 512 KiB가 좋은 위치 였지만 아직 SSD를 테스트하지 않았습니다.

    참고 : 매우 큰 버퍼는 성능 을 저하시키는 경향이 있음을 알았 습니다. 이전에 512-KiB 버퍼 대신 16-MiB 버퍼를 사용하여 속도 손실을 발견했습니다.

  • 파일을 열려면을 사용하십시오 _open(또는 _topenWindows가 올바른 경우) _write. 이것은 아마도 많은 버퍼링을 피할 것이지만 확실하지는 않습니다.

  • 사용하여 Windows 특정 기능을 좋아 CreateFile하고 WriteFile. 표준 라이브러리의 버퍼링을 피할 수 있습니다.


온라인에 게시 된 벤치 마크 결과를 확인하십시오. 적절한 처리량을 얻으려면 큐 깊이가 32 이상인 4kB 쓰기 또는 512K 이상의 쓰기가 필요합니다.
벤 Voigt

@ BenVoigt : 예, 512 KiB가 제게 달콤한 자리라고 말하면서 나와 관련이 있습니다. :)
user541686

예. 내 경험상, 작은 버퍼 크기가 일반적으로 최적입니다. FILE_FLAG_NO_BUFFERING큰 버퍼가 더 나은 경향이있는 사용하는 경우는 예외입니다 . 나는 FILE_FLAG_NO_BUFFERING거의 DMA 라고 생각하기 때문에 .
신비주의

22

std :: stream / FILE / device 사이에 차이가 없습니다. 버퍼링과 비 버퍼링 사이

참고 사항 :

  • SSD 드라이브는 가득 차면 속도가 느려져 "전송 속도가 느려집니다".
  • SSD 드라이브는 작동하지 않는 비트로 인해 오래 될수록 속도가 느려지는 경향이 있습니다 (전송 속도가 느림).

63 초 안에 코드가 실행되는 것을보고 있습니다.
따라서 전송 속도 : 260M / s (내 SSD는 사용자보다 약간 빠릅니다).

64 * 1024 * 1024 * 8 /*sizeof(unsigned long long) */ * 32 /*Chunks*/

= 16G
= 16G/63 = 260M/s

std :: fstream에서 FILE *로 이동하면 아무런 증가가 없습니다.

#include <stdio.h>

using namespace std;

int main()
{
    
    FILE* stream = fopen("binary", "w");

    for(int loop=0;loop < 32;++loop)
    {
         fwrite(a, sizeof(unsigned long long), size, stream);
    }
    fclose(stream);

}

따라서 C ++ 스트림은 기본 라이브러리가 허용하는 한 빨리 작동합니다.

그러나 OS를 OS 위에 구축 된 응용 프로그램과 비교하는 것은 불공평하다고 생각합니다. 응용 프로그램은 어떤 가정도 할 수 없으며 (드라이브가 SSD인지 알 수 없음) 따라서 OS의 파일 메커니즘을 사용하여 전송합니다.

OS는 어떤 가정도 할 필요가 없습니다. 관련된 드라이브 유형을 알려주고 데이터 전송을위한 최적의 기술을 사용할 수 있습니다. 이 경우 메모리를 메모리로 직접 전송하십시오. 메모리의 한 위치에서 다른 위치로 80G를 복사하는 프로그램을 작성하여 얼마나 빠른지보십시오.

편집하다

더 낮은 수준의 호출을 사용하도록 코드를 변경했습니다.
즉 버퍼링이 없습니다.

#include <fcntl.h>
#include <unistd.h>


const unsigned long long size = 64ULL*1024ULL*1024ULL;
unsigned long long a[size];
int main()
{
    int data = open("test", O_WRONLY | O_CREAT, 0777);
    for(int loop = 0; loop < 32; ++loop)
    {   
        write(data, a, size * sizeof(unsigned long long));
    }   
    close(data);
}

이것은 차이가 없었습니다.

참고 : 일반 드라이브가있는 경우 내 드라이브는 SSD 드라이브입니다. 위의 두 기술간에 차이가있을 수 있습니다. 그러나 비 버퍼링 및 버퍼링 (버퍼 크기보다 큰 청크를 쓸 때)은 아무런 차이가 없습니다.

편집 2 :

C ++에서 파일을 복사하는 가장 빠른 방법을 사용해 보셨습니까?

int main()
{
    std::ifstream  input("input");
    std::ofstream  output("ouptut");

    output << input.rdbuf();
}

5
공감하지는 않았지만 버퍼 크기가 너무 작습니다. OP가 사용하는 것과 동일한 512MB 버퍼로 처리했으며 스트림으로 20MB / s 대 90MB / s를 얻습니다 FILE*.
신비주의

또한 fwrite (a, sizeof (unsigned long long), size, stream); fwrite (a, 1, size * sizeof (부호없는 long long), pFile) 대신; 쓰기 당 64MB의 청크로 220MB / s를 제공합니다.
Dominic Hofer

2
@Mysticial : 버퍼 크기가 차이를 만든다는 사실에 놀랐습니다 (믿습니다). 버퍼는 작은 쓰기가 많을 때 기본 장치가 많은 요청으로 방해받지 않도록하는 데 유용합니다. 그러나 큰 청크를 작성할 때 (차단 장치에서) 쓰거나 읽을 때 버퍼가 필요하지 않습니다. 따라서 데이터는 기본 장치로 직접 전달되어야합니다 (따라서 버퍼를 우회). 비록 당신이 차이점을 본다면 이것은 이것과 모순되며 쓰기가 실제로 버퍼를 전혀 사용하지 않는 이유를 궁금하게 만듭니다.
Martin York

2
가장 좋은 해결책은 되지 버퍼 크기를 증가하지만, 버퍼 및 메이크업 쓰기가 기본 장치로 직접 데이터를 전달 제거 할 수 있습니다.
Martin York

1
@Mysticial : 1) 작은 덩어리가 없습니다 => 항상이 예에서는 충분히 큽니다. 이 경우 청크는 512M입니다. 2) 이것은 SSD 드라이브 (광산 및 OP)이므로 관련이 없습니다. 내 답변을 업데이트했습니다.
Martin York

13

가장 좋은 솔루션은 이중 버퍼링으로 비동기 쓰기를 구현하는 것입니다.

타임 라인을보십시오 :

------------------------------------------------>
FF|WWWWWWWW|FF|WWWWWWWW|FF|WWWWWWWW|FF|WWWWWWWW|

'F'는 버퍼를 채우는 시간을 나타내고 'W'는 디스크에 버퍼를 쓰는 시간을 나타냅니다. 따라서 버퍼를 파일에 쓰는 데 시간을 낭비하는 문제가 있습니다. 그러나 별도의 스레드에 쓰기를 구현하면 다음과 같이 바로 다음 버퍼를 채울 수 있습니다.

------------------------------------------------> (main thread, fills buffers)
FF|ff______|FF______|ff______|________|
------------------------------------------------> (writer thread)
  |WWWWWWWW|wwwwwwww|WWWWWWWW|wwwwwwww|

F-첫 번째 버퍼 채우기
f-두 번째 버퍼 채우기
W-첫 번째 버퍼를 파일에
쓰는 중 w-두 번째 버퍼를 파일에 쓰는 중 _-
작업이 완료되는 동안 대기

버퍼 스왑을 사용한이 접근 방식은 버퍼를 채우는 데 더 복잡한 계산이 필요하므로 시간이 더 많이 걸립니다. 나는 항상 내부에 비동기 쓰기를 숨기는 CSequentialStreamWriter 클래스를 구현하므로 최종 사용자에게는 인터페이스에 Write 함수가 있습니다.

버퍼 크기는 디스크 클러스터 크기의 배수 여야합니다. 그렇지 않으면 2 개의 인접 디스크 클러스터에 단일 버퍼를 작성하여 성능이 저하됩니다.

마지막 버퍼 쓰기
마지막으로 쓰기 기능을 호출 할 때 현재 버퍼가 채워지고 있는지 디스크에 기록해야합니다. 따라서 CSequentialStreamWriter에는 데이터의 마지막 부분을 디스크에 기록해야하는 Finalize (최종 버퍼 플러시)라고하는 별도의 메서드가 있어야합니다.

오류 처리.
코드가 두 번째 버퍼를 채우고 첫 번째 버퍼가 별도의 스레드에서 작성되고 있지만 어떤 이유로 쓰기가 실패하는 동안 주 스레드는 해당 오류를 인식해야합니다.

------------------------------------------------> (main thread, fills buffers)
FF|fX|
------------------------------------------------> (writer thread)
__|X|

CSequentialStreamWriter의 인터페이스에 Write 함수가 bool을 반환하거나 예외를 throw하여 별도의 스레드에 오류가 있다고 가정하고 그 상태를 기억해야하므로 다음 번 기본 스레드에서 Write 또는 Finilize를 호출하면 메소드가 반환됩니다 거짓이거나 예외를 던질 것입니다. 그리고 실패 후에 데이터를 미리 쓴 경우에도 버퍼 채우기를 중단 한 시점은 중요하지 않습니다. 대부분 파일이 손상되어 쓸모가 없습니다.


3
I / O를 계산과 병렬로 수행하는 것은 매우 좋은 생각이지만 Windows에서는 스레드를 사용하여 수행하지 않아야합니다. 대신 I / O 호출 중에 스레드 중 하나를 차단하지 않는 "중복 I / O"를 사용하십시오. 스레드 동기화에 대해 걱정할 필요가 거의 없습니다 (사용중인 I / O 작업이있는 버퍼에 액세스하지 마십시오).
벤 Voigt

11

파일 매핑을 시도하는 것이 좋습니다 . 내가 사용하는 mmapUNIX 환경에서, 과거에, 그리고 나는 내가 얻을 수있는 높은 성능에 깊은 인상을 받았습니다


1
@nalply 그것은 여전히 ​​명심해야 할 효과적이고 효율적이며 흥미로운 솔루션입니다.
얌 마르코비치

stackoverflow.com/a/2895799/220060 에 대한 mmap의 단점. 특히 "파일에 대한 순차 순차 액세스의 경우 항상 더 나은 솔루션은 아닙니다. [...]"또한 stackoverflow.com/questions/726471 은 32 비트 시스템에서 2 또는 3GB 그건 그렇고, 그 답을 내리는 사람은 내가 아닙니다.
nalply

8

FILE*대신 사용할 수 있고 얻은 성능을 측정 할 수 있습니까? 몇 가지 옵션은 다음 fwrite/write대신 사용하는 것입니다 fstream.

#include <stdio.h>

int main ()
{
  FILE * pFile;
  char buffer[] = { 'x' , 'y' , 'z' };
  pFile = fopen ( "myfile.bin" , "w+b" );
  fwrite (buffer , 1 , sizeof(buffer) , pFile );
  fclose (pFile);
  return 0;
}

를 사용하기로 결정한 경우 write비슷한 것을 시도하십시오.

#include <unistd.h>
#include <fcntl.h>

int main(void)
{
    int filedesc = open("testfile.txt", O_WRONLY | O_APPEND);

    if (filedesc < 0) {
        return -1;
    }

    if (write(filedesc, "This will be output to testfile.txt\n", 36) != 36) {
        write(2, "There was an error writing to testfile.txt\n", 43);
        return -1;
    }

    return 0;
}

또한 살펴 보라고 조언합니다 memory map. 그것은 당신의 대답 일 수 있습니다. 일단 데이터베이스에 저장하기 위해 20GB 파일을 다른 파일로 처리해야했고 파일이 열리지 않았습니다. 그래서 moemory map을 활용하는 솔루션입니다. 그래도 그렇게했습니다 Python.


실제로 FILE*동일한 512MB 버퍼를 사용하는 원본 코드와 동일한 기능이 최고 속도를 제공합니다. 현재 버퍼가 너무 작습니다.
Mysticial

1
@Mysticial 그러나 그것은 단지 예일뿐입니다.
cybertextron

대부분의 시스템에서 2표준 오류에 해당하지만 STDERR_FILENO대신 대신 사용 하는 것이 좋습니다 2. 또 다른 중요한 문제는 인터럽트 신호를 수신 할 때 발생할 수있는 오류 중 하나가 EINTR이라는 것입니다. 실제 오류가 아니며 단순히 다시 시도해야합니다.
Peyman

6

open () / write () / close () API 호출을 사용하고 출력 버퍼 크기를 실험 해보십시오. 전체 "다수 바이트"버퍼를 한 번에 전달하지 않고 몇 번의 쓰기 (즉, TotalNumBytes / OutBufferSize)를 수행해야합니다. OutBufferSize는 4096 바이트에서 메가 바이트까지 가능합니다.

다른 시도-WinAPI OpenFile / CreateFile을 사용 하고이 MSDN 기사 를 사용 하여 버퍼링을 해제 하십시오 (FILE_FLAG_NO_BUFFERING). 그리고 의 WriteFile에이 MSDN 문서 () 최적의 버퍼 크기를 알 수있는 드라이브의 블록 크기를 가져 오는 방법을 보여줍니다.

어쨌든 std :: ofstream은 래퍼이며 I / O 작업이 차단 될 수 있습니다. 전체 N- 기가 바이트 어레이를 순회하는 데에도 시간이 걸립니다. 작은 버퍼를 작성하는 동안 캐시에 도달하여 더 빠르게 작동합니다.


6

fstreams는 C 스트림보다 느리지 않지만 더 많은 CPU 를 사용합니다 (특히 버퍼링이 올바르게 구성되지 않은 경우). CPU가 포화되면 I / O 속도가 제한됩니다.

최소한 MSVC 2015 구현 은 스트림 버퍼가 설정되지 않은 경우 한 1 개의 문자를 출력 버퍼에 복사 합니다 (참조 streambuf::xsputn). 따라서 스트림 버퍼 (> 0)를 설정하십시오 .

fstream이 코드 를 사용하여 1500MB / s의 쓰기 속도 (M.2 SSD의 최고 속도)를 얻을 수 있습니다 .

#include <iostream>
#include <fstream>
#include <chrono>
#include <memory>
#include <stdio.h>
#ifdef __linux__
#include <unistd.h>
#endif
using namespace std;
using namespace std::chrono;
const size_t sz = 512 * 1024 * 1024;
const int numiter = 20;
const size_t bufsize = 1024 * 1024;
int main(int argc, char**argv)
{
  unique_ptr<char[]> data(new char[sz]);
  unique_ptr<char[]> buf(new char[bufsize]);
  for (size_t p = 0; p < sz; p += 16) {
    memcpy(&data[p], "BINARY.DATA.....", 16);
  }
  unlink("file.binary");
  int64_t total = 0;
  if (argc < 2 || strcmp(argv[1], "fopen") != 0) {
    cout << "fstream mode\n";
    ofstream myfile("file.binary", ios::out | ios::binary);
    if (!myfile) {
      cerr << "open failed\n"; return 1;
    }
    myfile.rdbuf()->pubsetbuf(buf.get(), bufsize); // IMPORTANT
    for (int i = 0; i < numiter; ++i) {
      auto tm1 = high_resolution_clock::now();
      myfile.write(data.get(), sz);
      if (!myfile)
        cerr << "write failed\n";
      auto tm = (duration_cast<milliseconds>(high_resolution_clock::now() - tm1).count());
      cout << tm << " ms\n";
      total += tm;
    }
    myfile.close();
  }
  else {
    cout << "fopen mode\n";
    FILE* pFile = fopen("file.binary", "wb");
    if (!pFile) {
      cerr << "open failed\n"; return 1;
    }
    setvbuf(pFile, buf.get(), _IOFBF, bufsize); // NOT important
    auto tm1 = high_resolution_clock::now();
    for (int i = 0; i < numiter; ++i) {
      auto tm1 = high_resolution_clock::now();
      if (fwrite(data.get(), sz, 1, pFile) != 1)
        cerr << "write failed\n";
      auto tm = (duration_cast<milliseconds>(high_resolution_clock::now() - tm1).count());
      cout << tm << " ms\n";
      total += tm;
    }
    fclose(pFile);
    auto tm2 = high_resolution_clock::now();
  }
  cout << "Total: " << total << " ms, " << (sz*numiter * 1000 / (1024.0 * 1024 * total)) << " MB/s\n";
}

나는 다른 플랫폼에서이 코드 (우분투, FreeBSD의)를 시도에는 I / O 속도의 차이를 발견 없지만, CPU 사용량 1 (8 약의 차이는 fstream사용 8 배 더 많은 CPU를 ). 따라서 디스크 fstream속도가 더 빠르면 쓰기 속도가 stdio버전 보다 빨리 느려질 수 있습니다.


3

메모리 매핑 파일을 사용해보십시오.


@Mehrdad 그러나 왜? 플랫폼에 의존하는 솔루션이기 때문에?
qehgt

3
아니요 ... 빠른 순차 파일 쓰기를 수행하려면 많은 양의 데이터를 한 번에 작성해야하기 때문입니다. (2MiB 청크가 좋은 출발점이 될 것입니다.) 메모리 매핑 된 파일을 사용하면 세분성을 제어 할 수 없으므로 메모리 관리자가 프리 페치 / 버퍼를 선택하기로 결정한 모든 것에 달려 있습니다. 일반적으로 ReadFile무작위 액세스의 경우에는 더 나은 결과를 얻을 수 있지만 순차 액세스의 경우 와 같이 일반적인 읽기 / 쓰기만큼 효과적이라고 본 적이 없습니다 .
user541686

그러나 메모리 매핑 된 파일은 예를 들어 페이징을 위해 OS에서 사용됩니다. 데이터를 읽고 쓰는 데 매우 최적화 된 (속도 측면에서) 방법이라고 생각합니다.
qehgt

7
@Mysticial : 사람들은 명백한 잘못을 많이 알고 있습니다.
Ben Voigt

1
@qehgt : 무엇이든 페이징은 순차 액세스보다 임의 액세스에 훨씬 더 최적화됩니다. 한 페이지의 데이터를 읽는 것이 한 번의 작업으로 1MB의 데이터를 읽는 것보다 훨씬 느립니다 .
user541686

3

탐색기에서 디스크 A에서 디스크 B로 무언가를 복사하면 Windows는 DMA를 사용합니다. 즉, 대부분의 복사 프로세스에서 CPU는 기본적으로 디스크 컨트롤러에 데이터를 어디에 넣을 것인지, 데이터를 가져 와서 체인의 전체 단계를 없애고 대량으로 이동하는 데 전혀 최적화되지 않은 것 외에는 아무것도하지 않습니다. 데이터-하드웨어를 의미합니다.

무엇 당신이 할 것은 CPU를 많이 포함한다. "[]을 (를) 채우는 일부 계산"을 알려 드리고자합니다. 내가 필수적이라고 생각합니다. a []를 생성 한 다음 a []에서 출력 버퍼로 복사 한 다음 (fstream :: write의 기능) 다시 생성합니다.

무엇을해야합니까? 멀티 스레딩! (멀티 코어 프로세서가 있기를 바랍니다)

  • 포크.
  • 하나의 스레드를 사용하여 [] 데이터 생성
  • 다른 하나를 사용하여 a []에서 디스크로 데이터 쓰기
  • 두 개의 배열 a1 [] 및 a2 []가 필요하며 이들 사이를 전환합니다.
  • 스레드 (세마포어, 메시지 큐 등)간에 일종의 동기화가 필요합니다.
  • Mehrdad가 언급 한 WriteFile 함수 와 같은 낮은 수준의 버퍼되지 않은 함수를 사용하십시오.

1

파일 스트림에 빠르게 쓰려면 읽기 버퍼를 더 크게 만들 수 있습니다.

wfstream f;
const size_t nBufferSize = 16184;
wchar_t buffer[nBufferSize];
f.rdbuf()->pubsetbuf(buffer, nBufferSize);

또한 많은 양의 데이터를 파일에 기록 할 때 파일을 논리적으로 확장 할 때 파일 크기 를 논리적으로 확장하는 것이 더 빠릅니다 . 파일 을 논리적으로 확장 할 때 파일 시스템은 파일을 쓰기 전에 새 공간을 0으로 만들지 않기 때문입니다. 또한 파일 확장을 막기 위해 실제로 필요한 것보다 파일을 논리적으로 확장하는 것이 좋습니다. 논리 파일 확장자 호출하여 Windows에서 지원 SetFileValidData또는 xfsctlXFS_IOC_RESVSP64XFS 시스템.


0

내 프로그램을 GNU / Linux 에서 gcc로 , mingw 에서 win 7로, xp로 승리하고 잘 작동했습니다.

내 프로그램을 사용하고 80GB 파일을 만들려면 33 줄을 다음과 같이 변경하십시오.

makeFile("Text.txt",1024,8192000);

프로그램을 종료하면 파일이 삭제되고 파일이 실행될 때 파일을 확인합니다

원하는 프로그램을 변경하기 만하면됩니다

firt 하나는 windows 프로그램이고 다른 하나는 GNU / Linux입니다.

http://mustafajf.persiangig.com/Projects/File/WinFile.cpp

http://mustafajf.persiangig.com/Projects/File/File.cpp

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.