Saturday 14 September 2019

Rdbuf binary options


Duedl0r: Sim. Mas isso é como dizer quotif o sol setsquot. Você pode correr realmente rápido oeste e você pode fazer o seu dia um pouco mais, mas o sol vai definir. A menos que você tenha bug e memória de vazamento (ele vai ficar fora do escopo). Mas uma vez que não há gerenciamento de memória dinâmica aqui não pode haver um vazamento e eles vão sair do escopo (assim como o sol vai definir). Ndash Loki Astari Jun 13 13 em 15:29 O buffer de maneira C ANSI é redundante, uma vez que um arquivo já está armazenado em buffer. (O tamanho deste buffer interno é o que BUFSIZ realmente define.) O OWN-BUFFER-C-WAY será lento como ele passa por fstream. Que faz um monte de despacho virtual, e novamente mantém buffers internos ou cada objeto de fluxo. (O COPY-ALGORITHM-C-WAY não sofre isso, como a classe streambufiterator ignora a camada de fluxo.) Eu prefiro o COPY-ALGORITHM-C-WAY, mas sem construir um fstream. Basta criar instâncias bare std :: filebuf quando nenhuma formatação real for necessária. Para o desempenho bruto, você não pode bater descritores de arquivos POSIX. Seu feio mas portátil e rápido em qualquer plataforma. A maneira Linux parece ser incrivelmente rápido, talvez o sistema operacional deixe a função retornar antes de E / S foi concluída Em qualquer caso, isso não é portátil suficiente para muitas aplicações. EDIT. Ah, o Linux nativo pode melhorar o desempenho ao intercalar leituras e gravações com E / S assíncrona. Letting comandos acumulam-se pode ajudar o driver de disco decidir quando é melhor procurar. Você pode tentar Boost Asio ou pthreads para comparação. Como para não pode bater descritores de arquivo POSIX bem isso é verdade se você está fazendo qualquer coisa com os dados, não apenas cegamente copiando. Resposta Aprendi que o sendfile64 foi desenvolvido para contornar essa limitação. Da página man: quotquotquot A chamada de sistema original do Linux sendfile () não foi projetada para lidar com grandes offsets de arquivos. Conseqüentemente, o Linux 2.4 adicionou sendfile64 (), com um tipo mais amplo para o argumento offset. A função wrapper glibc sendfile () lida transparentemente com as diferenças no kernel. quotquotquotquotquotquotqutquest rveale Apr 7 at 4: 26Estou tentando escrever enormes quantidades de dados no meu SSD (unidade de estado sólido). E por grandes quantidades quero dizer 80GB. Eu procurei na web soluções, mas o melhor que eu vim com era este: Compilado com o Visual Studio 2018 e otimizações completas e executar em Windows7 este programa maxes fora em torno de 20MB / s. O que realmente me incomoda é que o Windows pode copiar arquivos de outro SSD para este SSD em algum lugar entre 150MB / s e 200MB / s. Portanto, pelo menos 7 vezes mais rápido. É por isso que eu acho que eu deveria ser capaz de ir mais rápido. Todas as idéias como eu posso acelerar a minha escrita perguntou Jul 19 12 at 15:18 Tente o seguinte, em ordem: menor tamanho do buffer. Escrever 2 MiB de cada 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: Ive notado que muito grandes buffers tendem a diminuir o desempenho. Ive notado perdas de velocidade com o uso de 16-MiB buffers em vez de 512-KiB buffers antes. Use aberto (ou topen se você quiser ser Windows-correto) para abrir o arquivo, em seguida, use escrever. Isso provavelmente vai evitar um monte de buffer, mas não é certo. Usando funções específicas do Windows como CreateFile e WriteFile. Isso evitará qualquer buffer na biblioteca padrão. Não vejo diferença entre std :: stream / FILE / device. Entre buffer e não buffering. SSD unidades tendem a abrandar (taxas de transferência mais baixas) como eles se enchem. As unidades SSD tendem a diminuir a velocidade (taxas de transferência mais baixas) à medida que envelhecem (por causa de bits que não funcionam). Estou vendo o código ser executado em 63 secondds. Assim, uma taxa de transferência de: 260M / s (meu SSD olhar um pouco mais rápido que o seu). Eu recebo um não aumento, movendo para FILE de std :: fstream. Assim, o fluxo C está funcionando tão rápido quanto a biblioteca subjacente permitirá. Mas eu acho que é injusto comparar o sistema operacional a um aplicativo que é construído em cima 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 quaisquer suposições. Ele pode informar os tipos de unidades envolvidas e usar a técnica ideal para transferir os dados. Neste caso, uma memória direta para transferência de memória. Tente escrever um programa que copia 80G de 1 local na memória para outro e ver o quão rápido isso é. Eu mudei meu código para usar as chamadas de nível inferior: ou seja, sem buffer. Isso não fez diferença. NOTA . Minha unidade é uma unidade SSD, se você tem uma unidade normal, você pode ver uma diferença entre as duas técnicas acima. Mas como eu esperava não buffering e buffering (quando gravar grandes pedaços maiores do que o tamanho do buffer) não fazem diferença. Você já tentou o método mais rápido de copiar arquivos em C A melhor solução é implementar uma escrita assíncrona com buffer duplo. Observe a linha de tempo: O F representa o tempo para o preenchimento do buffer e W representa o tempo de gravação do buffer no disco. Portanto, o problema em desperdiçar tempo entre escrever buffers para arquivo. No entanto, ao implementar a escrita em um thread separado, você pode começar a preencher o próximo buffer imediatamente assim: F - preencher 1 buffer f - preencher 2 buffer W - escrever 1 buffer para arquivo w - escrever 2 buffer para arquivo - esperar enquanto operação É concluída Esta abordagem com swaps de buffer é muito útil quando o preenchimento de um buffer requer uma computação mais complexa (portanto, mais tempo). Eu sempre implementar uma classe CSequentialStreamWriter que oculta a escrita assíncrona no interior, por isso para o usuário final a interface tem apenas escrever função (s). E o tamanho do buffer deve ser um múltiplo do tamanho do cluster de disco. Caso contrário, você acabará com desempenho ruim, escrevendo um único buffer para 2 clusters de disco adjacentes. Escrever o último buffer. Quando você chamar a função de gravação pela última vez, você tem que se certificar de que o buffer atual está sendo preenchido deve ser gravado no disco também. Assim CSequentialStreamWriter deve ter um método separado, digamos Finalize (buffer final flush), que deve gravar no disco a última porção de dados. Tratamento de erros. Enquanto o código começa a preencher o segundo buffer, eo primeiro está sendo gravado em um thread separado, mas a gravação falha por algum motivo, o thread principal deve estar ciente dessa falha. Vamos supor que a interface de um CSequentialStreamWriter tem a função Write retorna bool ou lança uma exceção, tendo assim um erro em um thread separado, você tem que lembrar esse estado, então da próxima vez que você chamar Write ou Finilize no thread principal, o método retornará Falso ou lançará uma exceção. E realmente não importa em que ponto você parou de preencher um buffer, mesmo se você escreveu alguns dados à frente depois da falha - provavelmente o arquivo seria corrompido e inútil. O desempenho de E / S é paralelo com cálculos é uma idéia muito boa, mas no Windows você não deve usar threads para realizá-lo. Em vez disso, use QuotObjectado I / Oquot, 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 tem acesso a um buffer que tenha uma operação de E / S ativa usando). Ndash Ben Voigt May 3 15 at 15:46 Eu sugiro tentar mapeamento de arquivos. Eu usei o mmap no passado, em um ambiente UNIX, e fiquei impressionado com o alto desempenho que consegui. Tente usar chamadas de API open () / write () / close () e experimente o tamanho do buffer de saída. Quero dizer, não passe todo o buffer muitos-muitos-bytes de uma só vez, faça um par de gravações (ou seja, TotalNumBytes / OutBufferSize). OutBufferSize pode ser de 4096 bytes para megabyte. Outra tentativa - use WinAPI OpenFile / CreateFile e use este artigo MSDN para desativar buffering (FILEFLAGNOBUFFERING). E este artigo MSDN em WriteFile () mostra como obter o tamanho de bloco para a unidade para saber o tamanho de buffer ideal. De qualquer forma, std :: ofstream é um wrapper e pode haver bloqueio em operações de E / S. Tenha em mente que atravessar toda a matriz N-gigabyte também leva algum tempo. Enquanto você está escrevendo um pequeno buffer, ele chega ao cache e funciona mais rápido. Respondeu Jul 19 12 at 15:25 Você poderia usar FILE vez, ea medida do desempenho youve ganhou um par de opções é usar fwrite / write em vez de fstream: Se você decidir usar escrever. Tente algo semelhante: eu também aconselhá-lo a olhar para o mapa de memória. Essa pode ser sua resposta. Uma vez que eu tive que processar um arquivo de 20GB em outros para armazená-lo no banco de dados, eo arquivo como nem sequer abertura. Então, a solução para utilizar mapa moemory. Eu fiz isso em Python embora. Na verdade, um straight-forward FILE equivalente do código original usando o buffer de 512 MB mesmo chega a velocidade máxima. Seu buffer atual é muito pequeno. Ndash Mysticial Jul 19 12 at 15:53 ​​Mysticial Mas isso é apenas um exemplo. Ndash cybertextron Jul 19 12 at 15:54 Tente usar arquivos de memória mapeados. Respondeu Jul 19 12 at 15:43 Eu não acho que eles são uma boa idéia aqui. Ndash Mehrdad Jul 19 12 às 15:45 Mehrdad, mas porque Porque é uma solução dependente da plataforma ndash qehgt Jul 19 12 às 15:45 Não. It39s porque, a fim de fazer a escrita de arquivo rápido sequencial, você precisa escrever grandes quantidades de dados ao mesmo tempo . (Digamos, os pedaços de 2-MiB são provavelmente um bom ponto de partida.) Arquivos mapeados em memória não permitem que você controle a granularidade, então você está à mercê de qualquer que seja o gerente de memória que prefetar / armazenar buffer para você. Em geral, nunca os vi serem tão eficazes quanto a leitura / escrita normal com o ReadFile e tal para acesso seqüencial, embora para acesso aleatório eles possam muito bem ser melhores. Ndash Mehrdad Jul 19 12 at 15:48 Se você copiar algo do disco A para o disco B no explorador, o Windows emprega DMA. Isso significa que para a 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 de, eliminando um passo inteiro na cadeia, e que não é otimizado para mover grandes quantidades De dados - e quero dizer hardware. O que você faz envolve a CPU muito. Quero apontar para alguns cálculos para preencher uma parte. O que eu acho que é essencial. Você gera um, então você copia de um para um buffer de saída (isso é o que fstream :: write faz), então você gera novamente, etc. O que fazer Multithreading (eu espero que você tenha um processador multi-núcleo) garfo. Use um segmento para gerar dados Use o outro para gravar dados de um para o disco Você precisará de duas matrizes a1 e a2 e alternar entre eles Você precisará de algum tipo de sincronização entre seus segmentos (semáforos, fila de mensagens, etc.) As funções, como a função WriteFile mencionada por Mehrdad respondida Jul 19 12 at 16:33 fstream s não são mais lentos do que C fluxos, per se, mas eles usam mais CPU (especialmente se o buffer não está configurado corretamente). Quando uma CPU satura, limita a taxa de E / S. Pelo menos a implementação MSVC 2017 copia 1 char ao mesmo tempo para o 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). Eu posso obter uma velocidade de gravação de 1500MB / s (a velocidade total do meu SSD M.2) com fstream usando este código: Eu tentei este código em outras plataformas (Ubuntu, FreeBSD) e notou nenhuma diferença de taxa de E / S, mas um CPU diferença de uso de cerca de 8: 1 (fstream usado 8 vezes mais CPU). Assim, pode-se imaginar, se eu tivesse um disco mais rápido, o fstream escrever iria abrandar mais cedo do que a versão stdio. Se você quiser escrever rápido para fluxos de arquivos, então você poderia fazer o stream buffer de leitura maior: Além disso, ao escrever lotes de dados para arquivos que às vezes é mais rápido para logicamente estender o tamanho do arquivo em vez de fisicamente, este É porque quando logicamente estendendo um arquivo o sistema de arquivos não zera o novo espaço antes de escrever para ele. Também é inteligente para estender logicamente o arquivo mais do que você realmente precisa para evitar lotes de extentions arquivo. Extension de arquivo lógico é suportado no Windows chamando SetFileValidData ou xfsctl com XFSIOCRESVSP64 em sistemas XFS. Respondeu Mar 2 13 at 18:17 im compilando meu programa em gcc no GNU / Linux e mingw em win 7 e win xp e funcionou bem você pode usar o meu programa e para criar um arquivo de 80 GB apenas mudar a linha 33 para quando sair do Programa o arquivo será destruído, em seguida, verifique o arquivo quando ele está sendo executado para ter o programa que você quer apenas mudar o programa primeiro um é o programa do Windows eo segundo é para GNU / Linux Stack Exchange, IncComo ler em um arquivo em C Então uma pergunta simples, o que é a maneira correta de ler em um arquivo completamente em C Várias pessoas têm várias soluções, aqueles que usam a API C, C API, ou alguma variação de Truques com iteradores e algoritmos. Perguntando-se qual método é o mais rápido, eu pensei que poderia muito bem colocar as várias opções para o teste, e os resultados foram surpreendentes. Primeiro, deixe-me propor uma API que bem estar usando para a função. Bem enviar uma função de uma string C (char) de um nome de arquivo, e bem voltar uma string C (std :: string) do conteúdo do arquivo. Se o arquivo não pode ser aberto, bem lançar um erro por que é assim. Claro que você é bem-vindo para alterar essas funções para receber e retornar qualquer formato que você preferir, mas este é o protótipo bem estar operando: Nossa primeira técnica a considerar é usando a API C para ler diretamente em uma Cadeia de caracteres. Bem, abra um arquivo usando fopen (), calcule o tamanho do arquivo procurando o final e, em seguida, dimensione uma string apropriadamente. Bem ler o conteúdo na seqüência de caracteres e, em seguida, devolvê-lo. Estou dublando este método de técnica C. Esta é mais ou menos a técnica de qualquer proficiente C programador que prefere estilo C I / O seria semelhante. A próxima revisão bem técnica é basicamente a mesma idéia, mas usando fluxos C em vez disso. Estou dublando este método de técnica C. Mais uma vez, mais ou menos uma aplicação direta em C com base nos mesmos princípios de antes. A próxima técnica que as pessoas consideram está usando istreambufiterator. Este iterador é projetado para iteração muito rápida fora de buffers de fluxo (arquivos) em C. Este método é gostado por muitos por causa de como pouco código é necessário para implementá-lo, e você pode ler um arquivo diretamente em todos os tipos de contêineres, e não apenas cordas. O método também foi popularizado pelo livro Eficaz STL. Estou dublando o método de técnica iterador. Agora alguns têm olhado para a última técnica, e senti que poderia ser otimizado ainda mais, uma vez que se a seqüência de caracteres tem uma idéia de antecedência o quão grande ele precisa ser, ele vai realocar menos. Portanto, a idéia é reservar o tamanho da seqüência de caracteres, em seguida, puxar os dados dentro Vou chamar esta técnica atribuir método, uma vez que ele usa a função de atribuição de strings. Alguns questionaram a função anterior, como assign () em algumas implementações pode muito bem substituir o buffer interno e, portanto, não beneficiar de reserva. É melhor chamar pushback () em vez disso, o que manterá o buffer existente se não houver reatribuição necessária. Combinando std :: copy () e std :: backinserter (), podemos atingir nosso objetivo. Estou rotulando este método técnica cópia. Por fim, alguns querem tentar outra abordagem completamente. Os fluxos C têm algumas cópias muito rápidas para outro fluxo via operatorltlt em seus buffers internos. Portanto, podemos copiar diretamente em um fluxo de seqüência de caracteres e, em seguida, retornar a seqüência de caracteres que seqüência de caracteres usa. Bem chamar este método de técnica rdbuf. Agora qual é o método mais rápido para usar se tudo o que você realmente quer fazer é ler o arquivo em uma seqüência de caracteres e retorná-lo As velocidades exatas em relação a cada um pode variar de uma implementação para outra, mas as margens gerais entre as várias técnicas devem Ser semelhantes. Eu realizei meus testes com libstdc e GCC 4.6, o que você vê pode variar a partir desta. Eu testei com vários arquivos megabyte, lendo em um após o outro, e repetiu os testes uma dúzia de vezes e média dos resultados. Estes resultados são bastante interessantes. Não houve nenhuma diferença de velocidade em tudo se usando o C ou C API para ler um arquivo. Isso deve ser óbvio para todos nós, mas ainda assim muitas pessoas acham estranhamente que a API C tem menos sobrecarga. Os métodos diretos de baunilha também foram mais rápidos do que qualquer coisa envolvendo iteradores. C fluxo para copiar fluxo é muito rápido. Provavelmente só levou um pouco mais do que o método de baunilha devido a algumas realocações necessárias. Se você está fazendo arquivo de disco para o arquivo de disco, porém, você provavelmente quer considerar essa opção, e ir diretamente do fluxo para fora do fluxo. Usando os métodos istreambufiterator enquanto popular e concisa são realmente bastante lento. Claro theyre mais rápido do que istreamiterators (com pular desligado), mas eles não podem competir com métodos mais diretos. Uma função de atributo () de strings C, pelo menos em libstdc, parece jogar fora o buffer existente (no momento em que este texto é escrito), então reservar é mais inútil. Por outro lado, ler diretamente em uma seqüência de caracteres, ou um recipiente diferente para esse assunto, não é necessariamente sua solução mais ideal onde iteradores estão em causa. Usando a função externa std :: copy (), juntamente com a inserção de volta após a reserva é mais rápido do que a inicialização para cima. Você pode querer considerar este método para inserir em alguns outros recipientes. Na verdade, eu achei que std :: copy () de istreambufiterators com insertor de volta em um std :: deque para ser mais rápido do que inicialização reta até (81 vs 88.5), apesar de um Deque não ser capaz de reserva de antecedência Tal faz sentido com um Deque). Eu também achei que esta é uma maneira linda para obter um arquivo em um recipiente para trás, apesar de um Deque sendo bastante inútil para trabalhar com o conteúdo do arquivo. Agora vá lá fora e acelerar suas aplicações Se houver alguma demanda, eu vejo sobre a realização desses testes com outras implementações C. Os testes do iterador também variaram em seus tempos de execução entre 90 e 120, enquanto que os outros, ou os outros, foram testados com o cliv LLVM 3.0 e obtiveram o seguinte: C / C: 7.5 rdbuf: 31.5 copy: 97 assign: 102 iter: Com GCC, a variação entre os testes foi de uma diferença de 1-2. Tal como acontece com GCC, LLVM é inteligente o suficiente para ver que a reserva () seguido por assign () torna o primeiro uma op nulo e otimiza-lo. Ok, eu testei com o Visual C 2005. C: 18.3 C: 21 rdbuf: 199 iter: 209.3 atribuir: 221 cópia: 483.5 Algo me diz que o seu STL isn39t projetado muito bem, ou o compilador realmente isn39t inteligente o suficiente para otimizar tudo o que Modelo corretamente. Os resultados aqui também foram muito erráticos. Os tempos entre os testes variaram entre 2 e 40. I39ll tentar testar 2018 mais tarde. Interessante Estou surpreso com o mau desempenho das soluções 39heavier39 embora o desempenho nao VS / pode / ser devido a iteradores verificados. (Tem sido um longo tempo desde I39ve usado VS, mas IIRC que usou para habilitar iteradores verificados por padrão.) Poderia ser digno de comparar o desempenho de um mmap memcpy tipo solução (acho que impulsiona fornece uma memória mapeado arquivo wrapper em algum lugar). Ou para ver como EKOPath executa que usa o Apache STL. Se eu realmente queria a maneira mais rápida possível de ler em um arquivo, eu estaria usando POSIX 2008. Primeiro I39d abrir o arquivo, obter o seu tamanho, em seguida, dizer ao sistema operacional para otimizar para uma leitura seqüencial. Em seguida, I39d criar um buffer que está em sincronia com o fator de bloqueio da partição. Fazendo isso, facilmente cortaria o melhor tempo aqui pela metade. Mas I39m focando aqui no padrão C.

No comments:

Post a Comment