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.