2009-11-15 15 views
7

Me di cuenta que si imprimía una cadena larga (char *) usando cout, parece imprimir 1 carácter a la vez en Windows 7, Vista y Linux (usando masilla) usando 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 question hace que parezca que soy el único que tiene este problema.C++ cout printing slowly

Incluso escribí un reemplazo cout que parece que supera 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<<(char *b) 
    { 
     strncpy(buff+length, b, size-length); 
     unsigned int i = strlen(b); 
     if(i+length >= 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; 
} 

Cualquier idea por qué Court está imprimiendo tan lentamente para mí?

+0

Lo intenté en la computadora Linux nuevamente, y cout y rcout parecían tener la misma velocidad, pero sé que cout fue mucho más lento que printf en mi otra aplicación, así que estoy pensando que podría ser porque era multiproceso? Luego lo probé en mi comp de Vista y la grabación tardó unos 375 ms, mientras que el rcout tardó unos 100 ms. En la compilación de Windows 7 tomó 850 ms y rcout tomó alrededor de 70 ms. –

+0

'<< endl'? 'cout' no vacía automáticamente los datos. Es posible que se esté ejecutando en Windows al almacenar en búfer los datos de forma diferente a como lo hace con 'printf'.Pruebe también 'cerr' en lugar de' cout' y vea si hace una diferencia: si lo hace, el enjuague es definitivamente el problema. – quark

+0

cerr realizó lo mismo que cout, también haciendo un flush() después de que el cout no ayuda –

Respuesta

12

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

printfpodrí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í es un resumen de mi experimentación:

El número de instrucciones estática

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

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

El compilador de VC++ con optimizaciones, que genera código alrededor de 188 bytes. Pero, cuando lo reemplace printf-código basado, solo bytes son obligatorios.

El número de la instrucción ejecutada dinámicamente

El número de instrucciones estática simplemente cuenta la diferencia de 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 simple experimentación: Código

prueba:

int a = 1999; 
char b = 'a'; 
unsigned int c = 4200000000; 
long long int d =98765; 
long long unsigned int e = 123456789; 
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í es el resultado de Prueba1 (cout):

  • de instrucción ejecutada: 423.234.439

  • de la memoria cargas/tiendas: aprox. 320.000 y 980.000

  • tiempo transcurrido: 52 segundos

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

  • 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 el compilador, printf era mucho más rápido cout. 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 el tipo de comprobación es muy complicado.

bien, cout en MSVS es un asco :)

+0

Esto no es correcto; 'cout' no siempre es más rápido que' printf' de ninguna manera. Ver mi publicación para más detalles. –

+0

Corregí mi respuesta. Pero mis experimentos en Windows/Linux dan siempre consistencia. 'cout' es más lento que' printf'. También conté # de instrucción ejecutada. Sí, 'cout' necesitaba más que' printf'. En Linux, se necesitaba un 20% más de instrucciones para 'cout'. – minjang

+4

respuesta elegida para "Está bien, cout en MSVS simplemente apesta :)", tienes razón, ese es el problema –

8

Le sugiero que pruebe 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 mucho de funcionalidad incorporada que es necesaria para la interoperabilidad con otras clases que sobrecargan los operadores iostream.

Editar:

Cualquier persona que dice printf es siempre más rápido que std::cout es simplemente mal. 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 en realidad fue más rápido.

me dieron 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 compilador sabe en tiempo de compilación qué funciones necesita llamar para convertir enteros/flotantes/objetos en cadenas.

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

+1

También probé en Linux con icc -O3 en la máquina Xeon. Medido por 'tiempo' y poner'>/dev/null'. En cualquier caso, 'cout' requiere más instrucciones para completarse. Pero, las diferencias son pequeñas. Por ejemplo, cout 0.311 vs printf 0.218. Pero, estoy absolutamente de acuerdo, depende de la implementación. Edité mi respuesta. – minjang

+0

@minjang Creo que la prueba podría ser más significativa si no envía stdout a dev/null –

+0

@Ramonster, printf aún más rápido. Algunos detalles: compilado por g ++ w/-O3. cout tomó 4.9 segundos, pero printf tomó 4.5 segundos. No es una gran diferencia sin embargo. Pero, # de instrucciones ejecutadas son 775M para cout, 589M para printf. En realidad, las diferencias de 200M en las CPU modernas son bastante pequeñas. Además, debo suponer que cada instrucción tomaría un tiempo similar (sé que esto no es tan razonable). De todos modos, en mi experimentación, printf fue más rápido en Linux y Windows. – minjang

0

Pruebe usar endl o flush es, ya que vaciará el buffer cout, en caso de que el sistema operativo esté almacenando en caché la salida de su programa 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.

+0

He intentado usar endl y flush(), parece que no hacen la diferencia. Calculé la impresión y obtuve 842 ms para cout y 63 ms para mi rcout –

1

Según mi experiencia en concursos de programación, printf ES más rápido que cout.

Me acuerdo muchas veces cuando mi solución no lo hizo antes del límite de tiempo sólo por cin/cout, mientras 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.

+0

Nunca debería ser * que * mucho más lento, en la medida descrita por el OP. –

-2

Aquí es Hax que debe hacer C++ arroyos tan rápido como printf c. Nunca lo probé, pero creo que funciona.

ios_base::sync_with_stdio(0); 
+0

¿Nunca lo probé? – Tim

4

Intenta llamar ios::sync_with_stdio(false); antes de usar std :: cout/cin, a menos que, por supuesto, se mezcla stdio y iostream en su programa, que es un mal que hay que hacer.

+0

que no parece marcar la diferencia –

+0

¿Está seguro de estar utilizando la compilación "liberar/optimizar"? iostream tiende a ser mucho más lento en el modo de depuración debido al código de la plantilla. – obecalp

0

Usted debe tratar de escribir todos los datos en un ostringstream primero, y luego usar cout en el ostringstream 's str(). Estoy en Windows 7 de 64 bits y Test1 ya era significativamente más rápido que Test2 (su kilometraje puede variar). El uso de ostringstream para construir primero una sola cadena y luego usar cout en ese redujo aún más el tiempo de ejecución deTest1 en un factor de aproximadamente 3 a 4. Asegúrese de #include <sstream>.

es decir, sustituir

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 ostringstream hace de este modo mucho más rápido como consecuencia de no tratar de escribir en la pantalla cada vez que llame operator<< en 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 (de nuevo, su millaje puede variar).

por ejemplo,

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 218ms Foo3 tomó. ostingstream s son su amigo. 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 10% o menos; cout y printf son de hecho diferentes bestias bajo el capó).

Compilador: MinGW64 (TDM y sus bibliotecas incluidas).

0

Intente utilizar 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 corrientes c estándar. por ejemplo - std :: cin/wcin de iostream está sincronizado con stdin de c stream