Cin-Cout frente a Scanf-Printf

Los programadores competitivos habituales se enfrentan a un desafío común cuando la entrada es grande y la tarea de leer dicha entrada de stdin puede resultar un cuello de botella. Dicho problema va acompañado de «Advertencia: grandes datos de E/S».

Vamos a crear un archivo de entrada ficticio que contenga una línea con 16 bytes seguida de una nueva línea y que tenga 1000000 de esas líneas, hacer un archivo de 17 MB debería ser suficiente.

// Creating a dummy file of size 17 MB to compare 
// performance of scanf() and cin()
$ yes 1111111111111111 | head -1000000 > tmp/dummy

Comparemos el tiempo necesario para leer el archivo desde la entrada estándar (obtener el archivo del disco a la entrada estándar usando la redirección) usando scanf() versus cin.

// Filename : cin_test.cc to test the 
// We redirect above created temp file 
// of 17 MB to stdin when this program 
// is run.
#include<iostream>
using namespace std;
  
int main()
{
    char buffer[256];
    while (cin >> buffer)
    {
    }
    return 0;
}

Salida del programa anterior cuando el archivo ficticio se redirige a stdin.

$ g++ cin_test.cc –o cin_test
$ time ./cin_test < /tmp/dummy
real	 0m2.162s
user	 0m1.696s
sys	 0m0.332s
// Filename : scanf_test.c to see
// performance of scanf()
// We redirect above created temp file
// of 17 MB to stdin when this program
// is run.
#include<cstdlib>
#include<cstdio>
int main()
{
    char buffer[256];
    while (scanf("%s", buffer) != EOF)
    {
    }
    return 0;
}

Salida del programa anterior cuando el archivo ficticio se redirige a stdin.

$ g++ scanf_test.cc –o scanf_test
$ time ./scanf_test < /tmp/dummy
real	 0m0.426s
user	 0m0.248s
sys	 0m0.084s

Bueno, los resultados anteriores son consistentes con nuestras observaciones.

¿Por qué scanf es más rápido que cin?
En un alto nivel, ambos son envoltorios sobre la llamada al sistema read() , solo azúcar sintáctica. La única diferencia visible es que scanf() tiene que declarar explícitamente el tipo de entrada, mientras que cin tiene la operación de redirección sobrecargada usando plantillas. Esto no parece ser una buena razón para un impacto de rendimiento de 5x.

Resulta que iostream hace uso del sistema de almacenamiento en búfer de stdio . Por lo tanto, cin pierde tiempo sincronizándose con el búfer stdio de la biblioteca C subyacente , de modo que las llamadas tanto a scanf() como a cin se pueden intercalar.

Lo bueno es que libstdc++ proporciona una opción para desactivar la sincronización de todos los flujos estándar de iostream con sus flujos C estándar correspondientes usando

std::ios::sync_with_stdio(false);

y cin se vuelve más rápido que scanf() como debería haber sido.

Un artículo detallado sobre Fast Input Output en la programación competitiva

// Filename : cin_test_2.cc to see
// performance of cin() with stdio syc
// disabled using sync_with_stdio(false).
#include<iostream>
using namespace std;
  
int main()
{
    char buffer[256];
    ios_base::sync_with_stdio(false);
  
    while (cin >> buffer)
    {
  
    }
    return 0;
}

Ejecutando el programa:

$ g++ cin_test_2.cc –o cin_test_2
$ time./cin_test_2 </tmp/dummy
real    0m0.380s
user   0m0.240s
sys    0m0.028s 
  • Como con todas las cosas, hay una advertencia aquí. Con la sincronización desactivada, usar cin y scanf() juntos resultará en un desorden indefinido.
  • Con la sincronización desactivada, los resultados anteriores indican que cin es un 8-10 % más rápido que scanf() . Esto probablemente se deba a que scanf() interpreta los argumentos de formato en tiempo de ejecución y utiliza un número variable de argumentos, mientras que cin lo hace en tiempo de compilación.

Ahora me pregunto, ¿qué tan rápido se puede hacer?

// Redirecting contents of dummy file to null
// device (a special device that discards the
// information written to it) using command line.
$time cat /tmp/dummy > /dev/null
real   0m0.185s
user   0m0.000s
sys    0m0.092s

¡Guau! ¡¡¡Esto es rápido!!!

Este artículo es una contribución de Ayush Govil . Si le gusta GeeksforGeeks y le gustaría contribuir, también puede escribir un artículo y enviarlo por correo electrónico a contribuya@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks.
Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *