No sé si esto es cierto, pero cuando estaba leyendo las preguntas frecuentes sobre uno de los sitios de problemas, encontré algo que me llamó la atención:
Verifique sus métodos de entrada / salida. En C ++, usar cin y cout es demasiado lento. Úselos y garantizará que no podrá resolver ningún problema con una cantidad decente de entrada o salida. Utilice printf y scanf en su lugar.
¿Alguien puede aclarar esto? ¿Realmente está usando scanf () en programas C ++ más rápido que usando cin >> algo ? En caso afirmativo, ¿es una buena práctica usarlo en programas C ++? Pensé que era específico de C, aunque solo estoy aprendiendo C ++ ...
c++
c
performance
io
zeroDivisible
fuente
fuente
Respuestas:
Aquí hay una prueba rápida de un caso simple: un programa para leer una lista de números de entrada estándar y XOR todos los números.
versión iostream:
versión scanf:
Resultados
Usando un tercer programa, generé un archivo de texto que contenía 33,280,276 números aleatorios. Los tiempos de ejecución son:
Cambiar la configuración de optimización del compilador no pareció cambiar mucho los resultados.
Por lo tanto: realmente hay una diferencia de velocidad.
EDITAR: El usuario clyfish señala a continuación que la diferencia de velocidad se debe en gran medida a que las funciones de E / S iostream mantienen la sincronización con las funciones de CI / O. Podemos desactivar esto con una llamada a
std::ios::sync_with_stdio(false);
:Nuevos resultados:
¡C ++ iostream gana! Resulta que esta sincronización / descarga interna es lo que normalmente ralentiza la E / S de iostream. Si no estamos mezclando stdio e iostream, podemos desactivarlo y luego iostream es más rápido.
El código: https://gist.github.com/3845568
fuente
iostream
pierde cuando analiza más de un entero en unascanf
llamada.http://www.quora.com/Is-cin-cout-slower-than-scanf-printf/answer/Aditya-Vishwakarma
El rendimiento de
cin
/cout
puede ser lento porque necesitan mantenerse sincronizados con la biblioteca C subyacente. Esto es esencial si se van a utilizar tanto C IO como C ++ IO.Sin embargo, si solo va a usar C ++ IO, simplemente use la línea a continuación antes de cualquier operación de IO.
Para obtener más información al respecto, consulte los documentos libstdc ++ correspondientes .
fuente
Probablemente scanf sea algo más rápido que usar streams. Aunque las transmisiones brindan mucha seguridad de tipo y no tienen que analizar cadenas de formato en tiempo de ejecución, generalmente tiene la ventaja de no requerir asignaciones de memoria excesivas (esto depende de su compilador y tiempo de ejecución). Dicho esto, a menos que el rendimiento sea su único objetivo final y esté en la ruta crítica, entonces debería favorecer los métodos más seguros (más lentos).
Hay una muy delicioso artículo escrito aquí por Herb Sutter " Los formateadores de Cuerda de Manor Farm " que entra en muchos detalles del funcionamiento de formateadores de cuerda como
sscanf
ylexical_cast
y qué tipo de cosas estaban haciendo correr lentamente o rápidamente. Esto es un poco análogo, probablemente al tipo de cosas que afectarían el rendimiento entre el estilo C IO y el estilo C ++. La principal diferencia con los formateadores tendía a ser el tipo de seguridad y el número de asignaciones de memoria.fuente
Acabo de pasar una tarde trabajando en un problema en UVa Online (Factovisores, un problema muy interesante, échale un vistazo):
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=35&page=show_problem&problem=1080
Estaba recibiendo TLE (límite de tiempo excedido) en mis envíos. En estos sitios de jueces de resolución de problemas en línea, tiene un límite de tiempo de 2-3 segundos para manejar potencialmente miles de casos de prueba utilizados para evaluar su solución. Para problemas computacionalmente intensivos como este, cada microsegundo cuenta.
Estaba usando el algoritmo sugerido (leí en los foros de discusión del sitio), pero todavía recibía TLE.
Cambié solo "cin >> n >> m" a "scanf ("% d% d ", & n, & m)" y los pequeños "couts" pequeños a "printfs", ¡y mi TLE se convirtió en "Aceptado"!
Entonces, sí, puede hacer una gran diferencia, especialmente cuando los límites de tiempo son cortos.
fuente
Si le interesan tanto el rendimiento como el formato de cadenas, eche un vistazo a la biblioteca FastFormat de Matthew Wilson .
editar - enlace a la publicación accu en esa biblioteca: http://accu.org/index.php/journals/1539
fuente
Hay implementaciones stdio ( libio ) que implementa FILE * como un streambuf de C ++ y fprintf como un analizador de formato de tiempo de ejecución. IOstreams no necesita el análisis del formato de tiempo de ejecución, todo eso se realiza en tiempo de compilación. Entonces, con los backends compartidos, es razonable esperar que iostreams sea más rápido en tiempo de ejecución.
fuente
Sí, iostream es más lento que cstdio.
Sí, probablemente no deberías usar cstdio si estás desarrollando en C ++.
Dicho esto, hay formas aún más rápidas de obtener E / S que scanf si no le importa el formateo, escriba seguridad, bla, bla, bla ...
Por ejemplo, esta es una rutina personalizada para obtener un número de STDIN:
fuente
El problema es que
cin
conlleva una gran sobrecarga porque le brinda una capa de abstracción por encima de lasscanf()
llamadas. No debe usarscanf()
máscin
si está escribiendo software C ++ porque eso es lo que quierecin
. Si desea rendimiento, probablemente no estaría escribiendo E / S en C ++ de todos modos.fuente
cin
realmente más "abstracto" (en tiempo de ejecución) quescanf
? No lo creo ...scanf
debe interpretar la cadena de formato en tiempo de ejecución, mientras queiostream
conoce el formato en tiempo de compilación.std::istream
se configura en tiempo de ejecución (a través de manipuladores de E / S o mediante la configuración de indicadores en elistream
propio objeto). UnFILE*
objeto, por otro lado, no tiene ese estado, por lo que una llamada ascanf
este respecto es mucho más estable.Las declaraciones
cin
ycout
de uso general parecen ser más lento quescanf
yprintf
en C ++, pero en realidad son más rápidos!La cuestión es: en C ++, cada vez que usa
cin
ycout
, se lleva a cabo un proceso de sincronización de forma predeterminada que asegura que si usa ambosscanf
ycin
en su programa, ambos trabajan sincronizados entre sí. Este proceso de sincronización lleva tiempo. Por lo tanto,cin
ycout
parece ser más lento.Sin embargo, si el proceso de sincronización está configurado para no ocurrir,
cin
es más rápido quescanf
.Para omitir el proceso de sincronización, incluya el siguiente fragmento de código en su programa justo al comienzo de
main()
:Visite este sitio para más información.
fuente
Hay un error al final del archivo, pero este código C es dramáticamente más rápido que la versión C ++ más rápida.
El C ++ original tardó 30 segundos, el código C tardó 2 segundos.
fuente
Por supuesto, es ridículo usar cstdio sobre iostream. Al menos cuando desarrollas un software (si ya estás usando c ++ sobre c, entonces sigue todo el camino y usa sus beneficios en lugar de solo sufrir sus desventajas).
¡Pero en el juez en línea no está desarrollando software, está creando un programa que debería poder hacer cosas que el software de Microsoft tarda 60 segundos en lograr en 3 segundos!
Entonces, en este caso, la regla de oro es la siguiente (por supuesto, si no se mete en más problemas al usar Java)
fuente
Incluso si
scanf
fuera más rápido quecin
, no importaría. La gran mayoría de las veces, leerá desde el disco duro o el teclado. Obtener los datos sin procesar en su aplicación requiere órdenes de magnitud más tiempo del que tomascanf
ocin
procesarlos.fuente
iostream
es más lento que el disco duro. Sí, apesta tanto.