C ++ cout imprime lentamente

Noté que si imprimo una cadena larga (char *) usando cout, parece imprimir 1 carácter a la vez en la pantalla en Windows 7, Vista y Linux (usando masilla) utilizando Visual C ++ 2008 en Windows y G ++ en Linux. Printf es mucho más rápido. De hecho, cambié de cout a printf para la mayoría de las impresiones en un proyecto mío. Esto me confunde porque esta pregunta hace que parezca que soy el único que tiene este problema.

Incluso escribí un reemplazo de cout que parece que supera a los pantalones de cout en mi comp

class rcout { public: char buff[4096]; unsigned int size; unsigned int length; rcout() { size = 4096; length = 0; buff[0] = '\0'; } ~rcout() { printf("%s", buff); } rcout &operator<= size) { buff[size-1] = '\0'; printf("%s", buff); b += (size-length) -1; length = 0; return (*this) << b; } else length += i; return (*this); } rcout &operator<<(int i) { char b[32]; _itoa_s(i, b, 10); return (*this)<<b; } rcout &operator<<(float f) { char b[32]; sprintf_s(b, 32, "%f", f); return (*this)<<b; } }; int main() { char buff[65536]; memset(buff, 0, 65536); for(int i=0;i<3000;i++) buff[i] = rand()%26 + 'A'; rcout() << buff << buff <<"\n---"<< 121 <<"---" << 1.21f <<"---\n"; Sleep(1000); cout << "\n\nOk, now cout....\n\n"; cout << buff << buff <<"\n---"<< 121 <<"---" << 1.21f <<"---\n"; Sleep(1000); cout << "\n\nOk, now me again....\n\n"; rcout() << buff << buff <<"\n---"<< 121 <<"---" << 1.21f <<"---\n"; Sleep(1000); return 0; } 

¿Alguna idea de por qué la impresión es tan lenta para mí?

NOTA : Este resultado experimental es válido para MSVC. En alguna otra implementación de la biblioteca, el resultado variará.

printf podría ser (mucho) más rápido que cout . Aunque printf analiza la cadena de formato en tiempo de ejecución, requiere muchas menos llamadas de función y realmente necesita un número pequeño de instrucciones para hacer un mismo trabajo, en comparación con cout . Aquí hay un resumen de mi experimentación:

La cantidad de instrucciones estáticas

En general, cout genera mucho código que printf . Supongamos que tenemos el siguiente código de cout para imprimir con algunos formatos.

 os << setw(width) << dec << "0x" << hex << addr << ": " << rtnname << ": " << srccode << "(" << dec << lineno << ")" << endl; 

En un comstackdor de VC ++ con optimizaciones, genera un código de alrededor de 188 bytes. Pero cuando reemplaza su código basado en printf , solo se requieren 42 bytes.

La cantidad de instrucciones ejecutadas dinámicamente

La cantidad de instrucciones estáticas solo indica la diferencia del código binario estático. Lo que es más importante es la cantidad real de instrucciones que se ejecutan dinámicamente en tiempo de ejecución. También hice una experimentación simple:

Código de prueba:

 int a = 1999; char b = 'a'; unsigned int c = 4200000000; long long int d = 987654321098765; long long unsigned int e = 1234567890123456789; float f = 3123.4578f; double g = 3.141592654; void Test1() { cout << "a:" << a << “\n” << "a:" << setfill('0') << setw(8) << a << “\n” << "b:" << b << “\n” << "c:" << c << “\n” << "d:" << d << “\n” << "e:" << e << “\n” << "f:" << setprecision(6) << f << “\n” << "g:" << setprecision(10) << g << endl; } void Test2() { fprintf(stdout, "a:%d\n" "a:%08d\n" "b:%c\n" "c:%u\n" "d:%I64d\n" "e:%I64u\n" "f:%.2f\n" "g:%.9lf\n", a, a, b, c, d, e, f, g); fflush(stdout); } int main() { DWORD A, B; DWORD start = GetTickCount(); for (int i = 0; i < 10000; ++i) Test1(); A = GetTickCount() - start; start = GetTickCount(); for (int i = 0; i < 10000; ++i) Test2(); B = GetTickCount() - start; cerr << A << endl; cerr << B << endl; return 0; } 

Aquí está el resultado de Test1 (cout):

  • de instrucción ejecutada: 423,234,439

  • de cargas / almacenes de memoria: aprox. 320,000 y 980,000

  • Tiempo transcurrido: 52 segundos

Entonces, ¿qué pasa con printf ? Este es el resultado de Test2:

  • de instrucción ejecutada: 164,800,800

  • de cargas / almacenes de memoria: aprox. 70,000 y 180,000

  • Tiempo transcurrido: 13 segundos

En esta máquina y comstackdor, printf fue mucho más rápido. Tanto en el número de instrucciones ejecutadas, como en el # de carga / almacenamiento (indica el número de errores de caché), tienen de 3 a 4 diferencias.

Sé que este es un caso extremo. Además, debería tener en cuenta que cout es mucho más fácil cuando maneja datos de 32/64 bits y requiere independencia de la plataforma 32/64. Siempre hay una compensación. Estoy usando cout cuando verifico el tipo es muy complicado.

De acuerdo, cout en MSVS simplemente apesta 🙂

Sugeriría que intentes esta misma prueba en una computadora diferente. No tengo una buena respuesta sobre por qué esto podría estar pasando; todo lo que puedo decir es que nunca he notado una diferencia de velocidad entre cout y printf. También probé tu código usando gcc 4.3.2 en Linux y no hubo diferencia alguna.

Dicho esto, no puede reemplazar fácilmente a cout con su propia implementación. El hecho es que cout es una instancia de std :: ostream que tiene mucha funcionalidad incorporada que es necesaria para la interoperabilidad con otras clases que sobrecargan los operadores iostream.

Editar:

Cualquiera que diga printf siempre es más rápido que std::cout simplemente está equivocado. Acabo de ejecutar el código de prueba publicado por minjang, con gcc 4.3.2 y la bandera -O2 en un AMD Athlon X2 de 64 bits, y cout fue realmente más rápido .

Obtuve los siguientes resultados:

 printf: 00:00:12.024 cout: 00:00:04.144 

¿Es cout siempre más rápido que printf? Probablemente no. Especialmente no con implementaciones más antiguas. Pero en implementaciones más recientes es probable que iostreams sean más rápidos que stdio porque en lugar de analizar una cadena de formato en tiempo de ejecución, el comstackdor sabe en tiempo de comstackción qué funciones necesita llamar para convertir enteros / flotantes / objetos en cadenas.

Pero, lo que es más importante, la velocidad de printf versus cout depende de la implementación , por lo que el problema descrito por OP no es fácilmente explicable.

Pruebe call ios::sync_with_stdio(false); antes de usar std :: cout / cin, a menos que, por supuesto, mezcle stdio y iostream en su progtwig, lo cual es algo malo de hacer.

Basado en mi experiencia en competiciones de progtwigción, printf ES más rápido que cout.

Recuerdo muchas veces cuando mi solución no llegó antes del límite de tiempo solo por cin / cout , mientras que printf / scanf funcionó.

Además de eso, parece normal (al menos para mí) que cout sea ​​más lento que printf , porque realiza más operaciones.

Intente utilizar algunos endl o endl ya que eliminarán el búfer de cout , en caso de que el sistema operativo esté almacenando en caché la salida de su progtwig por cualquier razón. Pero, como dice Charles, no hay una buena explicación para este comportamiento, por lo que si eso no ayuda, es probable que sea un problema específico de su máquina.

ostringstream debe intentar escribir todos sus datos en un ostringstream , y luego usar cout en str() ostringstream . Estoy en Windows 7 de 64 bits y Test1 ya era significativamente más rápido que Test2 (su kilometraje puede variar). Usar un ostringstream para construir una sola cadena primero y luego usar cout en eso disminuyó aún más el tiempo de ejecución de Test1 en un factor de aproximadamente 3 a 4. Asegúrese de #include .

Es decir, reemplazar

 void Test1() { cout << "a:" << a << "\n" << "a:" << setfill('0') << setw(8) << a << "\n" << "b:" << b << "\n" << "c:" << c << "\n" << "d:" << d << "\n" << "e:" << e << "\n" << "f:" << setprecision(6) << f << "\n" << "g:" << setprecision(10) << g << endl; } 

con:

 void Test1() { ostringstream oss; oss << "a:" << a << "\n" << "a:" << setfill('0') << setw(8) << a << "\n" << "b:" << b << "\n" << "c:" << c << "\n" << "d:" << d << "\n" << "e:" << e << "\n" << "f:" << setprecision(6) << f << "\n" << "g:" << setprecision(10) << g << endl; cout << oss.str(); } 

Sospecho que ostringstream hace mucho más rápido como resultado de no intentar escribir en la pantalla cada vez que llamas al operator<< on cout . También he notado a través de la experiencia que reducir el número de veces que escribe en la pantalla (escribiendo más a la vez) aumenta el rendimiento (una vez más, su millaje puede variar).

P.ej,

 void Foo1() { for(int i = 0; i < 10000; ++i) { cout << "Foo1\n"; } } void Foo2() { std::string s; for(int i = 0; i < 10000; ++i) { s += "Foo2\n"; } cout << s; } void Foo3() { std::ostringstream oss; for(int i = 0; i < 10000; ++i) { oss << "Foo3\n"; } cout << oss.str(); } 

En mi caso, Foo1 tomó 1.092ms, Foo2 tomó 234ms, y Foo3 tomó 218ms. ostingstream s son tus amigos. Obviamente Foo2 y Foo3 requieren (trivialmente) más memoria. Para comparar esto con una función de estilo C, intente sprintf en un búfer y luego escriba ese búfer usando fprintf y verá aún más eficiencia sobre Test2 (aunque para mí esto solo mejoró el rendimiento de Test2 en aproximadamente un 10%; printf son de hecho diferentes bestias bajo el capó).

Comstackdor: MinGW64 (TDM y sus bibliotecas incluidas).

Intenta usar ios::sync_with_stdio(false); . Menciónelo antes de usar std :: cin / cout. No mezcla stdio o iostream, pero sincroniza streams estándar iostream con sus correspondientes streams c estándar. por ejemplo, std :: cin / wcin de iostream se sincroniza con stdin de c stream

Aquí está hax que debería hacer streams c ++ tan rápido como c printf. Nunca lo probé, pero creo que funciona.

 ios_base::sync_with_stdio(0);