El endl de C++ está definido para generar '\n' seguido de una descarga. flush() es una operación costosa, por lo que generalmente debe evitar usar endl como su final de línea predeterminado, ya que puede crear exactamente el problema de rendimiento que está viendo (y no solo con SMB, sino con cualquier flujo externo con un lavado costoso, incluido el giro local rust o incluso el último NVMe a una tasa de salida ridículamente alta).
Reemplazar endl con "\n" corregirá el rendimiento anterior al permitir que el sistema se almacene en el búfer según lo previsto. Excepto que algunas bibliotecas pueden vaciar en "\n", en cuyo caso tienes más dolores de cabeza (ver https://stackoverflow.com/questions/21129162/tell-endl-not-to-flush para una solución que anula el método sync() ).
Ahora, para complicar las cosas, flush() solo se define para lo que sucede dentro de los búferes de la biblioteca. El efecto del vaciado en el sistema operativo, el disco y otros búferes externos no está definido. Para Microsoft.NET "Cuando llama al método FileStream.Flush, el búfer de E/S del sistema operativo también se vacía". (https://msdn.microsoft.com/en-us/library/2bw4h516(v=vs.110).aspx) Esto hace que el enjuague sea particularmente costoso para Visual Studio C++, ya que hará que la escritura sea de ida y vuelta hasta los medios físicos en el otro extremo de su servidor remoto como está viendo. GCC, por otro lado, dice:"Un último recordatorio:generalmente hay más búferes involucrados que solo aquellos en el nivel de idioma / biblioteca. Los búferes del kernel, los búferes de disco y similares también tendrán un efecto. Inspeccionarlos y cambiarlos dependen del sistema ." (https://gcc.gnu.org/onlinedocs/libstdc++/manual/streambufs.html) Sus rastros de Ubuntu parecen indicar que los búferes del sistema operativo/red no son vaciados por la biblioteca flush(). El comportamiento dependiente del sistema sería una razón más para evitar endl y enjuagar en exceso. Si está usando VC++, puede intentar cambiar a un derivado de Windows GCC para ver cómo reaccionan los comportamientos dependientes del sistema o, alternativamente, usar Wine para ejecutar el ejecutable de Windows en Ubuntu.
De manera más general, debe pensar en sus requisitos para determinar si el lavado de cada línea es apropiado o no. endl generalmente es adecuado para secuencias interactivas como la pantalla (necesitamos que el usuario vea realmente nuestra salida, y no en ráfagas), pero generalmente no es adecuado para otros tipos de secuencias, incluidos archivos donde la sobrecarga de descarga puede ser significativa. He visto descargas de aplicaciones en cada escritura de 1 y 2 y 4 y 8 bytes... no es agradable ver que el sistema operativo procesa millones de IO para escribir un archivo de 1 MB.
Como ejemplo, es posible que un archivo de registro necesite vaciar cada línea si está depurando un bloqueo porque necesita vaciar el flujo antes de que ocurra el bloqueo; mientras que es posible que otro archivo de registro no necesite vaciar cada línea si solo produce un registro informativo detallado que se espera que se vacíe automáticamente antes de que finalice la aplicación. No es necesario que sea uno u otro, ya que podría derivar una clase con un algoritmo de descarga más sofisticado para satisfacer requisitos específicos.
Compare su caso con el caso contrastante de las personas que necesitan asegurarse de que sus datos se conserven por completo en el disco y no sean vulnerables en un búfer del sistema operativo (https://stackoverflow.com/questions/7522479/how-do-i-ensure-data -está-escrito-en-disco-antes-de-cerrar-fstream).
Tenga en cuenta que, tal como está escrito, outFile.flush() es superfluo ya que vacía un flujo de salida ya vaciado. Para ser pedante, debería haber usado endl solo o preferiblemente "\n" con outFile.flush() pero no ambos.
El rendimiento de las operaciones de archivos remotos, como lectura/escritura, mediante el protocolo SMB puede verse afectado por el tamaño de los búfer asignados por servidores y clientes. El tamaño del búfer determina el número de viajes de ida y vuelta necesarios para enviar una cantidad fija de datos. Cada vez que se envían solicitudes y respuestas entre el cliente y el servidor, la cantidad de tiempo necesario es igual al menos a la latencia entre ambos lados, lo que podría ser muy significativo en el caso de la red de área amplia (WAN).
Búfer SMB:MaxBufferSize se puede configurar a través de la siguiente configuración de registro:
HKLM\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters\SizeReqBuf
Tipo de datos:REG_DWORD
Rango:1024 a 65535 (Elija el valor según sus requisitos por encima de 5000)
PERO SMB SIGNING afecta al tamaño máximo de búfer permitido. Por lo tanto, también debemos deshabilitar la firma SMB para lograr nuestro objetivo. El siguiente registro debe crearse en el lado del servidor y, si es posible, también en el lado del cliente.
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\LanManWorkstation\Parameters
Nombre del valor:EnableSecuritySignature
Tipo de datos:REG_DWORD
Datos:0 (deshabilitar), 1 (habilitar)
No tengo suficiente reputación para dejar un comentario (que creo que sería mejor dado el nivel de verificación de esta respuesta).
Observé que una gran variación en el seguimiento de nivel de Linux frente a Windows es que está usando SMB1 en Linux y SMB2 en Windows. Quizás el mecanismo de bloqueo por lotes funcione mejor en SMB1 samba que en la implementación de arrendamiento exclusivo de SMB2. En ambos casos, deberían permitir cierta cantidad de almacenamiento en caché del lado del cliente.
1) Tal vez intente establecer un nivel de protocolo máximo más bajo en Samba para probar Windows con SMB12) Valide que se eliminen los bloqueos operativos exclusivos o las concesiones
Espero que esto ayude :)