¿Declaración de variables detrás del bucle o dentro del bucle? - página 11

 
Vict:

Lo he buscado, resulta que ningún compilador de https://en.cppreference.com/w/cpp/compiler_support ha terminado los módulos, así que no hay nada que ver.

Aún así, he conseguido utilizar los módulos a través de clang

// module
export module M;
export int f(int x) {
    return 2 + x;
}

// main.cc
import M;
int main() {
        for(int i = 0;  i < 1000000;  ++ i)
                f(5);
}

Compilado con optimización, el bucle no se ejecutó en absoluto (es decir, la optimización se realiza entre: unidad de traducción + módulos semiconectados, en lugar de sólo una unidad de traducción como antes). Sin ningún tipo de LTO. El candidato de std c++ se mueve completamente a los módulos, imho, y no habrá preguntas: "por qué tan lento en este ejemplo artificial con bucle desnudo".

 
Alexey Navoykov:

Así que parece que se ha dado cuenta de que asigna y borra memoria cada vez incluso en este caso:


Por cierto, puede que haya dado resultados erróneos la última vez. Lo más probable es que fuera en modo x86. Ahora estoy probando en modo x64 y los resultados por C++ son mucho mejores:

1) ~ 2000 mseg.

2) ~ 200 ms (es 3 veces más rápido).

Aunque también actualicé Studio a la última versión, debe haber influido también ya que incluso x86 es más rápido ahora que las pruebas anteriores.

Bueno, ahora C++ no pierde tan vergonzosamente ante Sharp. sólo por 3 veces aproximadamente )

Hmm, así que no hay recolector de basura, ¿cuál es la cuestión de la definición?

No hablo de velocidad, hablo de memoria
 
Alexey Navoykov , resulta que constexpr string y vector fueron arrastrados a c++20. Es decir, todas nuestras pruebas no tomarán ni una sola instrucción para servir una cadena, por ejemplo, asignar memoria, etc. (bueno, si los símbolos no vienen de la época temprana, por supuesto). Genial.
 
Vict:
Alexey Navoykov , resulta que constexpr string y vector fueron arrastrados a C++20. Es decir, todas estas pruebas no tomarán ni una sola instrucción para el mantenimiento de las cadenas, por ejemplo, asignar memoria, etc. (bueno, si los símbolos no vienen de la época temprana, por supuesto). Genial.

¿Es necesario marcar explícitamente todo como constexpr o lo detectará automáticamente?

Tal y como yo lo veo, el problema no está en la norma, sino en el compilador, ¿hay algo que le impida recortar ahora lo innecesario? Especialmente extraño es que el compilador de Sharp optimice con normalidad, mientras que la versión plus del mismoMicrosoft falle. Aunque parece que deberían tener una base común (en cuanto a la optimización de dichas construcciones)

 
Alexey Navoykov:

¿Es necesario marcar explícitamente todo como constexpr o lo detectará automáticamente?

El std es automático, basta con que la cadena obtenga las cadenas que se conocen en tiempo de compilación. Todas las operaciones (buscar, reemplazar, ...) con esta cadena serán las mismas en tiempo de compilación (sospecho que sharp y mcl contaron nuestros ejemplos en tiempo de compilación también). El plan es hacer todos los contenedores constepxr. Es decir, ya no depende del estado de ánimo del compilador, sino que está garantizado por la norma, podemos calcular el parámetro de la plantilla mediante el análisis sintáctico de cadenas, por ejemplo. Esto es lo interesante - resulta que new/delete ahora también constexpr (para tipos constexpr)?

Según me parece, el problema no está en la norma sino en el compilador, ¿algo le impide recortar cosas innecesarias? Especialmente extraño es el hecho de que el compilador Sharp optimiza normalmente y la versión plus del mismo Microsoft falla, aunque parece que deben tener una base común (en cuanto a la optimización de dichas construcciones)

Plus tiene una desventaja en cuanto a las posibilidades de optimización: sólo está dentro de una unidad de traducción (si no utilizamos LTO). Por supuesto que se puede hacer todo el std en los archivos de cabecera, pero no lo hacen (por el tiempo de compilación ?). Sharp con módulos es más avanzado en este sentido. Pero c++20 también solucionará esto pronto con la llegada de los módulos. También planea trasladar la std allí (primero depurarán los módulos y luego la escribirán). Pero VS parece que ya ha hecho std en los módulos, puede probarlo (dejó el enlace de arriba).

Pero sigo insistiendo - es mejor declarar después del bucle (bueno, si no es un tipo fundamental).

 
Alexey Navoykov:

Decidí probarlo también en C# por curiosidad. No sólo los resultados son casi iguales en velocidad, sino que también funcionan mucho más rápido que en C++.

Resultados:

Suma: 894782460, Tiempo: 69 ms.

Suma: 894782460, Tiempo: 56 ms

Y aquí hay un análogo en C++:

Suma: 894782460, Tiempo: 2947 ms

Suma: 894782460, Tiempo: 684 ms

Lo pruebo en VS 2019,toda la optimización está habilitada .

Que se joda tal C++).

p.s. Los resultados en C# varían agradablemente de una prueba a otra, pero en promedio ambas variantes son igualmente rápidas.

Sugerencia: en sharpe string es el tipo base, en pluses es una clase escrita en pluses. En la variante de Sharpe la asignación de la cadena se hace una vez, en los pluses - 10e6 veces. Al final, los pluses son más rápidos, pero hay que ser inteligente a la hora de escribir el código, no hacer una joroba como los indios de Boeing.
 
SeriousRacoon:
Sugerencia: En sharpe, string es el tipo base, en pluses es una clase escrita en pluses. En la variante de Sharpe la asignación de cadenas se hace una vez, en los pluses - 10e6 veces. Al final, las ventajas son más rápidas, pero hay que poner en marcha el cerebro al escribir el código en lugar de hacer una joroba como los indios de Boeing.
No, no se trata de eso. Simplemente me olvidé de que en la cadena hay una clase y es la referencia la que se asigna, no el objeto en sí. Por lo tanto, la comparación es incorrecta de esta forma
 

Por cierto, hablando de optimización. ¿Quiere que el compilador optimice algo aquí?

mutex mtx;

void thread_0() {
        while (true) {
                do_task_0();
                {
                        lock_guard<mutex> lck{mtx};
                        do_task_1();
                }
                do_task_2();
                {
                        lock_guard<mutex> lck{mtx};
                        do_task_3();
                }
                do_task_4();
        {
}
void thread_1() {
        while (true) {
                do_task_5();
                {
                        lock_guard<mutex> lck{mtx};
                        do_task_6();
                }
                do_task_7();
                {
                        lock_guard<mutex> lck{mtx};
                        do_task_8();
                }
                do_task_9();
        {
}
 
Alexey Navoykov:
No, el punto es bastante diferente allí. Acabo de olvidar que la cadena es una clase allí y es una referencia que se asigna, no el objeto en sí. Así que la comparación es incorrecta en esta forma
¿Dónde se asigna la referencia (puntero)? ¿En la cadena de la clase plus? ¿Qué quiere decir que la selección del buffer y la copia tienen lugar allí.
 
SeriousRacoon:
¿Dónde se asigna la referencia (puntero)? ¿En la cadena de la clase plus? ¿Qué quieres decir con que es la selección del buffer y la copia?

está hablando de sharp

Razón de la queja: