Escrevendo um arquivo binário em C ++ muito rápido

241

Estou tentando gravar grandes quantidades de dados no meu SSD (solid state drive). E por grandes quantidades, quero dizer 80GB.

Naveguei na Web em busca de soluções, mas o melhor que surgiu foi o seguinte:

#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();
}

Compilado com o Visual Studio 2010 e otimizações completas e executado no Windows7, esse programa atinge o máximo de 20 MB / s. O que realmente me incomoda é que o Windows pode copiar arquivos de um outro SSD para esse SSD em algo entre 150 MB / se 200 MB / s. Então, pelo menos 7 vezes mais rápido. É por isso que acho que devo poder ir mais rápido.

Alguma idéia de como posso acelerar minha redação?

Dominic Hofer
fonte
11
Seus resultados de tempo excluíram o tempo necessário para realizar seus cálculos para preencher um []?
catchmeifyoutry
7
Na verdade, eu já fiz essa tarefa antes. Usando simples, fwrite()eu poderia obter cerca de 80% das velocidades de gravação de pico. Somente com FILE_FLAG_NO_BUFFERINGeu consegui velocidade máxima.
Mysticial 19/07/12
10
Não tenho certeza se é justo comparar sua gravação de arquivo com uma cópia de SSD para SSD. Pode ser que o SSD para SSD funcione em um nível inferior, evitando as bibliotecas C ++ ou usando o acesso direto à memória (DMA). Copiar algo não é o mesmo que gravar valores arbitrários em um arquivo de acesso aleatório.
19412 Igor F.
4
@IgorF .: Isso é especulação errada; é uma comparação perfeitamente justa (se nada mais, a favor da gravação de arquivos). Copiar através de uma unidade no Windows é apenas leitura e gravação; nada extravagante / complicado / diferente acontecendo por baixo.
user541686
5
@MaximYegorushkin: Link ou não aconteceu. : P
user541686

Respostas:

233

Isso fez o trabalho (no ano de 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;
}

Acabei de cronometrar 8 GB em 36 segundos, que é de cerca de 220 MB / se acho que isso maximiza meu SSD. Vale ressaltar também que o código na pergunta usou um núcleo 100%, enquanto esse código usa apenas 2-5%.

Muito obrigado a todos.

Atualização : 5 anos se passaram é 2017 agora. Compiladores, hardware, bibliotecas e meus requisitos foram alterados. Foi por isso que fiz algumas alterações no código e fiz algumas novas medições.

Primeiro o código:

#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;
}

Esse código é compilado com o Visual Studio 2017 e o g ++ 7.2.0 (um novo requisito). Eu executei o código com duas configurações:

  • Notebook, Core i7, SSD, Ubuntu 16.04, g ++ Versão 7.2.0 com -std = c ++ 11 -march = nativo -O3
  • Desktop, Core i7, SSD, Windows 10, Visual Studio 2017 Versão 15.3.1 com / Ox / Ob2 / Oi / Ot / GT / GL / Gy

O que forneceu as seguintes medidas (após a redução dos valores de 1 MB, por serem óbvios outliers): insira a descrição da imagem aqui insira a descrição da imagem aqui Ambas as vezes a opção 1 e a opção 3 maximizam meu SSD. Eu não esperava que isso acontecesse, porque a opção 2 costumava ser o código mais rápido na minha máquina antiga naquela época.

TL; DR : Minhas medidas indicam que o uso std::fstreamacabou FILE.

Dominic Hofer
fonte
8
+1 Sim, foi a primeira coisa que tentei. FILE*é mais rápido que fluxos. Eu não esperava essa diferença, já que "deveria" ter sido ligada à E / S de qualquer maneira.
Mysticial 19/07/12
12
Podemos concluir que a E / S no estilo C é (estranhamente) muito mais rápida que os fluxos C ++?
SCHPPININ
21
@ SChepurin: Se você está sendo pedante, provavelmente não. Se você está sendo prático, provavelmente sim. :)
user541686
10
Você poderia, por favor, explicar (para um burro de C ++ como eu) a diferença entre as duas abordagens, e por que essa funciona muito mais rápido que a original?
Mike Chamberlain
11
Anexar ios::sync_with_stdio(false);faz alguma diferença para o código com fluxo? Só estou curioso para saber a diferença entre usar essa linha e não, mas não tenho o disco rápido o suficiente para verificar a caixa da esquina. E se houver alguma diferença real.
Artur Czajka
24

Tente o seguinte, em ordem:

  • Tamanho menor do buffer. Escrever ~ 2 MiB por vez pode ser um bom começo. No meu último laptop, ~ 512 KiB foi o ponto ideal, mas ainda não testei no meu SSD.

    Nota: Observei que buffers muito grandes tendem a diminuir o desempenho. Notei perdas de velocidade com o uso de buffers de 16 MiB em vez de buffers de 512 KiB antes.

  • Use _open(ou _topense você deseja corrigir o Windows) para abrir o arquivo e use _write. Isso provavelmente evitará muito buffer, mas não é certo.

  • Usando funções específicas do Windows como CreateFilee WriteFile. Isso evitará qualquer buffer na biblioteca padrão.

user541686
fonte
Verifique todos os resultados de benchmark publicados online. Você precisa de gravações de 4kB com uma profundidade de fila de 32 ou mais, ou gravações de 512K ou superior, para obter qualquer tipo de rendimento decente.
21412 Ben Voigt
@BenVoigt: Sim, isso se correlaciona comigo dizendo que 512 KiB foi o ponto ideal para mim. :)
user541686
Sim. Pela minha experiência, tamanhos de buffer menores geralmente são ótimos. A exceção é quando você está usando FILE_FLAG_NO_BUFFERING- no qual buffers maiores tendem a ser melhores. Desde que eu acho que FILE_FLAG_NO_BUFFERINGé praticamente DMA.
Mysticial 19/07/12
22

Não vejo diferença entre std :: stream / FILE / device. Entre buffer e não buffer.

Observe também:

  • As unidades SSD "tendem" a desacelerar (taxas de transferência mais baixas) à medida que são preenchidas.
  • As unidades SSD "tendem" a desacelerar (taxas de transferência mais baixas) à medida que envelhecem (devido a bits que não estão funcionando).

Estou vendo o código executado em 63 segundos.
Assim, uma taxa de transferência de: 260M / s (meu SSD parece um pouco mais rápido que o seu).

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

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

Não recebo nenhum aumento movendo para FILE * do std :: fstream.

#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);

}

Portanto, o fluxo C ++ está funcionando tão rápido quanto a biblioteca subjacente permitirá.

Mas acho injusto comparar o sistema operacional com um aplicativo que é construído no topo do sistema operacional. O aplicativo não pode fazer suposições (ele não sabe que as unidades são SSD) e, portanto, usa os mecanismos de arquivo do sistema operacional para transferência.

Enquanto o sistema operacional não precisa fazer nenhuma suposição. Ele pode dizer os tipos de unidades envolvidas e usar a técnica ideal para transferir os dados. Nesse caso, uma transferência direta de memória para memória. Tente escrever um programa que copie 80G de 1 local na memória para outro e veja quão rápido é.

Editar

Mudei meu código para usar as chamadas de nível inferior:
ou seja, sem buffer.

#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);
}

Isso não fez diferença.

NOTA : Minha unidade é uma unidade SSD. Se você tiver uma unidade normal, poderá ver uma diferença entre as duas técnicas acima. Mas, como eu esperava, o buffer e o buffer (ao gravar grandes pedaços maiores que o tamanho do buffer) não fazem diferença.

Edição 2:

Você já tentou o método mais rápido de copiar arquivos em C ++

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

    output << input.rdbuf();
}
Martin York
fonte
5
Não reduzi o voto, mas o tamanho do seu buffer é muito pequeno. Fiz isso com o mesmo buffer de 512 MB que o OP está usando e recebo 20 MB / s com fluxos versus 90 MB / s com FILE*.
Mysticial
Também o seu caminho com fwrite (a, sizeof (sem assinatura, long long), size, stream); em vez de fwrite (a, 1, size * sizeof (sem assinatura, long long), pFile); dá-me 220 MB / s com pedaços de 64 MB por gravação.
Dominic Hofer
2
@Mysticial: Surpreende meu tamanho do buffer que faz a diferença (embora eu acredite em você). O buffer é útil quando você tem muitas gravações pequenas, para que o dispositivo subjacente não seja incomodado com muitos pedidos. Mas quando você está escrevendo grandes blocos, não há necessidade de um buffer ao escrever / ler (em um dispositivo de bloqueio). Como tal, os dados devem ser passados ​​diretamente para o dispositivo subjacente (ignorando o buffer). Embora se você vê uma diferença, isso contradiz isso e me pergunto por que a gravação está realmente usando um buffer.
Martin York
2
A melhor solução é NÃO aumentar o tamanho do buffer, mas removê-lo e fazer com que a gravação passe os dados diretamente para o dispositivo subjacente.
Martin York
1
@Mysticial: 1) Não há pequenos pedaços => Ele sempre é grande o suficiente (neste exemplo). Nesse caso, os pedaços são 512M 2) Esta é uma unidade SSD (tanto a mina quanto a OP), portanto nada disso é relevante. Eu atualizei minha resposta.
1913 Martin Martin
13

A melhor solução é implementar uma gravação assíncrona com buffer duplo.

Veja a linha do tempo:

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

O 'F' representa o tempo de preenchimento do buffer e o 'W' representa o tempo de gravação do buffer no disco. Portanto, o problema de perder tempo entre gravar buffers no arquivo. No entanto, implementando a gravação em um thread separado, você pode começar a preencher o próximo buffer imediatamente assim:

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

F - preenchendo o 1º buffer
f - preenchendo o 2º buffer
W - escrevendo o 1º buffer no arquivo
w - escrevendo o 2º buffer no arquivo
_ - aguarde enquanto a operação está concluída

Essa abordagem com trocas de buffer é muito útil quando o preenchimento de um buffer requer computação mais complexa (portanto, mais tempo). Eu sempre implementei uma classe CSequentialStreamWriter que oculta a gravação assíncrona por dentro; portanto, para o usuário final, a interface possui apenas funções de gravação.

E o tamanho do buffer deve ser múltiplo do tamanho do cluster de disco. Caso contrário, você terá um desempenho ruim gravando um único buffer em 2 clusters de disco adjacentes.

Escrevendo o último buffer.
Quando você chama a função Write pela última vez, você deve garantir que o buffer atual esteja sendo preenchido também deve ser gravado no disco. Portanto, CSequentialStreamWriter deve ter um método separado, digamos Finalize (final buffer flush), que deve gravar no disco a última parte dos dados.

Manipulação de erros.
Enquanto o código começa a preencher o segundo buffer e o 1º está sendo gravado em um thread separado, mas a gravação falha por algum motivo, o thread principal deve estar ciente dessa falha.

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

Vamos supor que a interface de um CSequentialStreamWriter tenha a função Write retorna bool ou lança uma exceção, portanto, com um erro em um thread separado, você deve se lembrar desse estado; portanto, da próxima vez que você chamar Write ou Finilize no thread principal, o método retornará False ou lançará uma exceção. E realmente não importa em que ponto você parou de preencher um buffer, mesmo se você escrevesse alguns dados antes da falha - provavelmente o arquivo estaria corrompido e inútil.

HandMadeOX
fonte
3
Executar E / S é paralelo aos cálculos é uma boa ideia, mas no Windows você não deve usar threads para realizá-lo. Em vez disso, use "E / S sobreposta", que não bloqueia um de seus segmentos durante a chamada de E / S. Isso significa que você quase não precisa se preocupar com a sincronização de threads (apenas não acesse um buffer que possui uma operação de E / S ativa).
Ben Voigt
11

Eu sugiro tentar o mapeamento de arquivos . Eu usei mmapno passado, em um ambiente UNIX, e fiquei impressionado com o alto desempenho que consegui alcançar

Ralph
fonte
1
@nalply Ainda é uma solução funcional, eficiente e interessante a ser lembrada.
Yam Marcovic
stackoverflow.com/a/2895799/220060 sobre os prós e contras do mmap. Observe especialmente "Para acessos seqüenciais puros ao arquivo, nem sempre é a melhor solução". Também stackoverflow.com/questions/726471 , diz efetivamente que em um sistema de 32 bits você está limitado a 2 ou 3 GB. - a propósito, não sou eu quem votou contra essa resposta.
Nalply
8

Em FILE*vez disso, você poderia usar e medir o desempenho obtido? Algumas opções são para usar em fwrite/writevez de 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;
}

Se você decidir usar write, tente algo semelhante:

#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;
}

Eu também aconselho você a procurar memory map. Essa pode ser a sua resposta. Uma vez eu tive que processar um arquivo de 20 GB em outro para armazená-lo no banco de dados, e o arquivo como nem mesmo abrindo. Portanto, a solução é utilizar o mapa de memória. Eu fiz isso no Pythonentanto.

cybertextron
fonte
Na verdade, um FILE*equivalente direto do código original, usando o mesmo buffer de 512 MB, obtém velocidade máxima. Seu buffer atual é muito pequeno.
Mysticial 19/07/12
1
@Mysticial Mas isso é apenas um exemplo.
22812
Na maioria dos sistemas, 2corresponde a erro padrão, mas ainda é recomendável que você use em STDERR_FILENOvez de 2. Outra questão importante é que um possível erro que você pode obter é o EINTR; quando você recebe um sinal de interrupção, esse não é um erro real e você deve simplesmente tentar novamente.
Peyman
6

Tente usar as chamadas de API open () / write () / close () e experimente o tamanho do buffer de saída. Quero dizer, não passe o buffer inteiro de "muitos bytes" de uma só vez, faça algumas gravações (ou seja, TotalNumBytes / OutBufferSize). OutBufferSize pode ser de 4096 bytes a megabyte.

Outra tentativa - use o WinAPI OpenFile / CreateFile e use este artigo do MSDN para desativar o buffer (FILE_FLAG_NO_BUFFERING). E este artigo do MSDN sobre WriteFile () mostra como obter o tamanho do bloco para a unidade saber o tamanho ideal do buffer.

De qualquer forma, std :: ofstream é um invólucro e pode estar bloqueando as operações de E / S. Lembre-se de que percorrer toda a matriz N-gigabyte também leva algum tempo. Enquanto você escreve um pequeno buffer, ele chega ao cache e funciona mais rápido.

Viktor Latypov
fonte
6

fstreams não são mais lentos que os fluxos C, por si só, mas usam mais CPU (especialmente se o buffer não estiver configurado corretamente). Quando uma CPU satura, limita a taxa de E / S.

Pelo menos, a implementação do MSVC 2015 copia 1 caracter por vez no buffer de saída quando um buffer de fluxo não está definido (consulte streambuf::xsputn). Portanto, certifique-se de definir um buffer de fluxo (> 0) .

Posso obter uma velocidade de gravação de 1500MB / s (a velocidade total do meu SSD M.2) fstreamusando este código:

#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";
}

Eu tentei esse código em outras plataformas (Ubuntu, FreeBSD) e não notei diferenças na taxa de E / S, mas uma diferença de uso da CPU de cerca de 8: 1 ( fstreamusada 8 vezes mais CPU ). Então, pode-se imaginar, se eu tivesse um disco mais rápido, a fstreamgravação diminuiria mais cedo que a stdioversão.

rustyx
fonte
3

Tente usar arquivos mapeados na memória.

qehgt
fonte
@Mehrdad mas por quê? Porque é uma solução dependente da plataforma?
Qdhgt 19/07
3
Não ... é porque, para fazer uma gravação sequencial rápida de arquivos, você precisa gravar grandes quantidades de dados de uma só vez. (Por exemplo, pedaços de 2 MiB provavelmente são um bom ponto de partida.) Os arquivos mapeados na memória não permitem controlar a granularidade; portanto, você está à mercê de tudo o que o gerenciador de memória decidir pré-buscar / armazenar em buffer para você. Em geral, nunca os vi tão eficientes quanto a leitura / gravação normal ReadFilepara acessos sequenciais, embora para acessos aleatórios possam ser melhores.
user541686
Mas os arquivos mapeados na memória são usados ​​pelo SO para paginação, por exemplo. Eu acho que é uma maneira altamente otimizada (em termos de velocidade) de ler / gravar dados.
Qdhgt
7
Saber' Pessoas" um monte de coisas que são simplesmente errado simples: @Mysticial.
Ben Voigt
1
@qehgt: Se alguma coisa, a paginação é muito mais otimizada para acesso aleatório do que o acesso seqüencial. Ler 1 página de dados é muito mais lento do que ler 1 megabyte de dados em uma única operação.
user541686
3

Se você copiar algo do disco A para o disco B no explorer, o Windows empregará DMA. Isso significa que, na maior parte do processo de cópia, a CPU basicamente não fará nada além de dizer ao controlador de disco onde colocar e obter dados, eliminando uma etapa inteira da cadeia e uma que não é otimizada para mover grandes quantidades. de dados - e eu quero dizer hardware.

O que você faz envolve muito a CPU. Quero apontar para a parte "Alguns cálculos para preencher uma []". O que eu acho que é essencial. Você gera um [], depois copia de um [] para um buffer de saída (é o que o fstream :: write faz), depois gera novamente etc.

O que fazer? Multithreading! (Espero que você tenha um processador multi-core)

  • garfo.
  • Use um thread para gerar dados []
  • Use o outro para gravar dados de um [] no disco
  • Você precisará de duas matrizes a1 [] e a2 [] e alternar entre elas
  • Você precisará de algum tipo de sincronização entre seus threads (semáforos, fila de mensagens etc.)
  • Use funções de nível inferior, sem buffer, como a função WriteFile mencionada por Mehrdad
dualizado
fonte
1

Se você deseja gravar rapidamente em fluxos de arquivos, pode tornar o buffer de leitura maior:

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

Além disso, ao gravar muitos dados em arquivos, às vezes é mais rápido estender logicamente o tamanho do arquivo em vez de fisicamente, porque, ao estender logicamente um arquivo, o sistema de arquivos não zera o novo espaço antes de gravá-lo. Também é inteligente estender logicamente o arquivo mais do que o necessário para evitar muitas extensões de arquivo. A extensão de arquivo lógico é suportada no Windows chamando SetFileValidDataou xfsctlcom XFS_IOC_RESVSP64sistemas XFS.


fonte
0

estou compilando meu programa em gcc no GNU / Linux e mingw no win 7 e win xp e funcionou bem

você pode usar o meu programa e criar um arquivo de 80 GB basta alterar a linha 33 para

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

Quando sair do programa, o arquivo será destruído e, em seguida, verifique o arquivo quando estiver em execução.

ter o programa que você quer apenas mudar o programa

primeiro é o programa windows e o segundo é para GNU / Linux

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

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

Ethaan
fonte