O endl C ++ é definido para saída '\ n' seguido por um flush. flush () é uma operação cara, então você deve geralmente evitar usar endl como seu final de linha padrão, pois ele pode criar exatamente o problema de desempenho que você está vendo (e não apenas com SMB, mas com um ofstream com flush caro incluindo spinning local). ferrugem ou até mesmo o último NVMe em alguma taxa ridiculamente alta de produção).
Substituir endl por "\ n" corrigirá o desempenho acima, permitindo que o sistema faça o buffer como pretendido. Exceto que algumas bibliotecas podem liberar "\ n", caso em que você tem mais dores de cabeça (consulte link para uma solução substituindo o método sync ().
Agora, para complicar as coisas, flush () é definido apenas para o que acontece nos buffers da biblioteca. O efeito de liberação no sistema operacional, disco e outros buffers externos não está definido. Para o Microsoft.NET "Quando você chama o método FileStream.Flush, o buffer de E / S do sistema operacional também é liberado." ( link ) Isso torna o flush particularmente caro para o Visual Studio C ++ como ele fará a viagem de ida e volta até a mídia física na extremidade do servidor remoto, como você está vendo. O GCC, por outro lado, diz "Um último lembrete: há geralmente mais buffers envolvidos do que apenas aqueles no nível de linguagem / biblioteca. Buffers de kernel, buffers de disco e similares também terão efeito. Inspecionar e alterar esses são dependentes do sistema " ( link ) Seus rastreamentos do Ubuntu parecem indicar que os buffers do sistema operacional / rede não são liberados pela biblioteca flush (). Comportamento dependente do sistema seria mais uma razão para evitar endl e flushing excessivamente. Se você estiver usando o VC ++, pode tentar alternar para um derivativo do Windows GCC para ver como os comportamentos dependentes do sistema reagem ou, alternativamente, usar o Wine para executar o executável do Windows no Ubuntu.
Mais geralmente, você precisa pensar sobre seus requisitos para determinar se a liberação de cada linha é apropriada ou não. O endl é geralmente adequado para fluxos interativos, como o display (precisamos que o usuário realmente veja nossa saída e não em rajadas), mas geralmente não é adequado para outros tipos de fluxos, incluindo arquivos em que a sobrecarga de liberação pode ser significativa. Já vi apps flush em todas as gravações de 1 e 2 e 4 e 8 bytes ... não é bonito ver o SO triturar milhões de IOs para gravar um arquivo de 1 MB.
Como exemplo, um arquivo de log pode precisar liberar cada linha se você estiver depurando uma falha, porque você precisa liberar o fluxo antes de ocorrer a falha; enquanto outro arquivo de log pode não precisar liberar todas as linhas se estiver produzindo um registro informativo detalhado que deve ser executado automaticamente antes que o aplicativo seja encerrado. Não precisa ser ou / ou como você pode derivar uma classe com um algoritmo flush mais sofisticado para atender a requisitos específicos.
Compare seu caso com o caso contrastante de pessoas que precisam garantir que seus dados sejam completamente mantidos em disco e não vulneráveis em um buffer do sistema operacional ( link ).
Observe que, conforme escrito, outFile.flush () é supérfluo, pois libera um fluxo de dados já liberado. Para ser pedante, você deve ter usado endl sozinho ou de preferência "\ n" com outFile.flush (), mas não ambos.