Introducción: La paradoja de la velocidad que explotó Stack Overflow
\n\nImagínese la situación: está resolviendo un problema de olimpiada o procesando un archivo de registro de gigabytes. El script en Python se ejecuta en 2 segundos. Lo reescribe en C++, esperando una aceleración diez veces mayor, pero… ¡obtiene 10 segundos! ¿Un dolor familiar? Precisamente esta pregunta obtuvo miles de visitas en Stack Overflow y generó una discusión legendaria: «Why is reading lines from stdin much slower in C++ than Python?».
\n\nParecería, ¿cómo puede el «rápido» C++ perder contra el «lento» Python en una operación tan trivial como leer líneas? La respuesta no está en la velocidad del lenguaje en sí, sino en la configuración predeterminada y la arquitectura de iostream. En este artículo, realizaremos nuestra propia investigación, escribiremos código de prueba en C++ y Python, mediremos el tiempo y, lo más importante, aprenderemos a hacer que la entrada/salida en C++ sea realmente rápida.
\n\nEste artículo no es teoría seca, sino una guía práctica para todos los que escriben en C++ y se enfrentan a problemas de rendimiento de entrada/salida. ¡Allá vamos!
\n\nEl núcleo del problema: ¿Por qué iostream «se ralentiza»?
\n\nCuando escribe std::cin >> data o std::getline(std::cin, line), C++ por defecto hace algo que muchos ni siquiera imaginan. Sincroniza sus flujos de entrada/salida con los flujos estándar de C (stdin, stdout). ¿Para qué? Para compatibilidad: puede usar simultáneamente printf y std::cout en un mismo programa, y la salida no se mezclará.
Esta sincronización tiene un costo elevado. Cada llamada a cin o cout verifica el estado de los flujos de C, lo que convierte una operación rápida con búfer en una lenta y sincrónica.
En Python, en cambio, es diferente. La función input() y sys.stdin.readline() utilizan su propio búfer, bien optimizado a nivel de C. Sin sincronización adicional — solo lectura de un bloque de datos desde el descriptor de archivo. Precisamente por eso, la lectura desde stdin en Python puede ser más rápida que en C++ «de fábrica».
Experimento: Prueba de velocidad
\n\nVerifiquemos esto en la práctica. Escribamos un programa simple que lea 1,000,000 de líneas desde stdin y no haga nada con ellas (solo leerlas). Primero en C++ «tal cual»:
\n\n// slow_cin.cpp\n#include <iostream>\n#include <string>\n\nint main() {\n std::ios::sync_with_stdio(false); // Por ahora lo comentamos\n std::cin.tie(nullptr); // Y esto también\n\n std::string line;\n while (std::getline(std::cin, line)) {\n // No hacemos nada\n }\n return 0;\n}\n\nY ahora en Python:
\n\n# fast_python.py\nimport sys\n\ndef main():\n for line in sys.stdin:\n pass\n\nif __name__ == "__main__":\n main()\n\nEjecutemos la prueba con seq 1000000 | ./slow_cin y seq 1000000 | python3 fast_python.py. El resultado será impactante: ¡C++ sin optimizaciones puede ser de 5 a 10 veces más lento que Python! Pero no se apresure a enterrar a C++ — el problema se resuelve con dos líneas de código.
Solución: Dos líneas mágicas
\n\nTodo lo que se necesita para acelerar la entrada/salida en C++ es desactivar la sincronización y la vinculación de flujos. Agregue al inicio de main():
std::ios::sync_with_stdio(false);\nstd::cin.tie(nullptr);\n\nLa primera línea desactiva la sincronización entre iostream y stdio. La segunda desvincula cin de cout (por defecto, antes de cada operación de entrada, cout vacía su búfer, lo que también ralentiza el trabajo). Después de esto, su código en C++ comenzará a funcionar a la par de Python, y a menudo incluso más rápido.
Verificamos el resultado
\n\nAhora descomente estas líneas en nuestra prueba y ejecútelo de nuevo. Verá que el rendimiento de C++ se dispara. En algunos benchmarks, la diferencia alcanza 10 veces.