Pregunta

He estado usando el rendimiento en muchas de mis programas en Python, y realmente aclara el código en muchos casos. Me blogs sobre ella y es una de las páginas más populares de mi sitio.

C # también ofrece rendimiento -. Que se implementa a través del estado de mantenimiento en el lado del llamante, hecho a través de una clase generada automáticamente que mantiene el estado, las variables locales de la función, etc.

Actualmente estoy leyendo sobre C ++ 0x y sus complementos; y al leer acerca de la implementación de lambdas en C ++ 0x, me entero de que se realiza a través de las clases generadas automáticamente también, equipado con el operador () registrar el código de lambda. La pregunta natural formado en mi mente:? Lo hicieron por lambdas, ¿por qué no lo consideren para el apoyo de "rendimiento", también

Seguramente puede ver el valor de co-rutinas ... así que sólo puedo adivinar que piensan implementaciones basadas en macro (por ejemplo, de Simon Tatham) como un sustituto adecuado. No son, sin embargo, por muchas razones:.-Destinatario de la llamada mantenido estado, no reentrante, con sede en macro (que por sí solo es motivo suficiente), etc.

Editar: yield no depende de la recolección de basura, hilos o fibras. Puede leer el artículo de Simon al ver que yo estoy hablando del compilador de hacer una transformación sencilla, como por ejemplo:

int fibonacci() {
    int a = 0, b = 1;
    while (true) {
        yield a;
        int c = a + b;
        a = b;
        b = c;
    }
}

En:

struct GeneratedFibonacci {
    int state;
    int a, b;

    GeneratedFibonacci() : state (0), a (0), b (1) {}

    int operator()() {
        switch (state) {
        case 0:
            state = 1;
            while (true) {
                return a;

        case 1:
                int c = a + b;
                a = b;
                b = c;
            }
        }
    }
}

La recolección de basura? No. hilos? No. Las fibras? Nº transformación simple? Podría decirse que sí.

¿Fue útil?

Solución

  

Lo hicieron por lambdas, ¿por qué no lo consideran para apoyar el rendimiento, también?

papeles . ¿Alguien se propone?

  

... sólo puede adivinar que consideran implementaciones basadas en macro a ser un sustituto adecuado.

No necesariamente. Estoy seguro de que saben existen tales soluciones macro, pero su sustitución no es motivación suficiente, por sí sola, para obtener nuevas características pasaron.


A pesar de que hay varias cuestiones en torno a una nueva palabra clave, los que podrían superarse mediante una nueva sintaxis, tal como se hizo para lambdas y el uso de automóviles como un tipo de retorno de la función.

radicalmente nuevas características necesitan los conductores fuertes (es decir, personas) para analizar a fondo y las características de empuje a través del comité, ya que siempre tienen un montón de gente escéptica de un cambio radical. Así que incluso en ausencia de lo que se ven como una fuerte razón técnica contra un constructo de rendimiento, no pueden todavía no han sido suficiente apoyo.

Pero fundamentalmente, la biblioteca estándar de C ++ ha adoptado un concepto diferente de iteradores de lo que uno ve con el rendimiento. Comparar a los iteradores de Python, que sólo requieren dos operaciones:

  1. an_iter.next () devuelve el siguiente artículo o plantea StopIteration (next () incorporado incluido en 2,6 en lugar de utilizar un método)
  2. iter (an_iter) devuelve an_iter (para que pueda tratar iterables e iteradores de forma idéntica en funciones)
iteradores

C ++ 's se utilizan de dos en dos (que debe ser del mismo tipo), se dividen en categorías, sería un cambio semántico a la transición en algo más susceptible a una construcción de rendimiento, y que el cambio no encajaría bien con conceptos (que desde entonces se ha dejado caer, pero que llegó relativamente tarde). Por ejemplo, véase la razón para (con razón, si decepcionantemente) rechazar mi comentario sobre el cambio de los bucles a una forma que harían escribir esta forma diferente de iterador mucho más fácil a base de gama.

Para aclarar concretamente lo que quiero decir acerca de las diferentes formas de iterador: sus necesidades de ejemplo de código generados otro tipo a ser el tipo más iterador maquinaria asociada para conseguir y mantener los iteradores. No es que no podía ser manejada, pero no es tan simple como usted puede imaginar en un principio. La complejidad real es la "transformación simple" respetando las excepciones para las variables "locales" (incluyendo durante la construcción), que controlan la duración de las variables "locales" en los ámbitos locales dentro del generador (la mayoría tendría que ser salvados a través de llamadas), y así sucesivamente.

Otros consejos

No puedo decir por qué no añadir algo como esto, pero en el caso de lambdas, no eran solo añadieron a la lengua tampoco.

Se comenzó su vida como una implementación de la biblioteca en Boost, que demostró que

  • lambdas son ampliamente útil: mucha gente va a usar cuando están disponibles, y que
  • una implementación de la biblioteca en C ++ 03 sufre una serie de deficiencias.

En base a esto, el comité decidió adoptar algún tipo de lambdas en C ++ 0x, y yo creo que al principio experimentaron con la adición de un lenguaje más general presenta para permitir que un mejor implementación de la biblioteca que tiene Boost.

Y finalmente, se hizo una característica del lenguaje básico, porque no tenían otra opción:. Porque no era posible hacer un lo suficientemente bueno implementación de la biblioteca

Las nuevas características del lenguaje principal no se añaden simplemente a la lengua, ya que parece como una idea buena. El comité es muy reacios a añadir, y la función de que se trate realmente tiene que demostrar su valía. Se debe demostrar que la función es:

  • posible implementar en el compilador,
  • va a resolver una necesidad real, y
  • que una implementación de la biblioteca no sería lo suficientemente bueno.

En el caso de que si una palabra clave yield, sabemos que el primer punto se puede resolver. Como se ha mostrado, es bastante simple transformación que se puede hacer mecánicamente.

El segundo punto es complicado. ¿Cuánto de un necesidad para esto es que hay? Cómo ampliamente utilizados son las implementaciones de bibliotecas que existen? ¿Cuántas personas han pedido esto, o presentado propuestas para ello?

El último punto parece pasar también. Al menos en C ++ 03, una implementación de la biblioteca sufre algunos defectos, como usted ha señalado, que podría justificar una implementación del lenguaje núcleo. Se podría hacer una aplicación mejor biblioteca en C ++ 0x sin embargo?

Así que sospecho que el problema principal es realmente una falta de interés. C ++ es un lenguaje ya enorme, y nadie quiere que crezca más grande a menos que las características que se agregan son realmente vale la pena. Sospecho que esto simplemente no es lo suficientemente útil.

Añadir una palabra clave siempre es complicado, ya que invalida código válido anteriormente. Intenta evitar que, en un lenguaje con una base de código tan grande como C ++.

La evolución de C ++ es un proceso público. Si se siente yield debería estar ahí, formular una solicitud apropiada para el comité de C ++ estándar.

Usted recibirá su respuesta, directamente de las personas que tomaron la decisión.

Así que parece que no lo hacen en C ++ 11, 14 o C ++, pero podría estar en camino a C ++ 17. Echar un vistazo a la conferencia C ++ corrutinas, un negativo sobrecarga abstracción de CppCon2015 y el documento aquí .

Para resumir, están trabajando para extender C ++ funciones para tener rendimiento y esperar como características de las funciones. Parece que tienen una implementación inicial en Visual Studio 2015, no estoy seguro si sonido metálico tiene una aplicación aún. También parece que su puede haber algunos problemas con el uso de rendimiento y esperar que las palabras claves.

La presentación es interesante porque habla de lo mucho que simplifica código de red, en la que está esperando los datos entren en para continuar la secuencia de procesamiento. Sorprendentemente, parece que el uso de estos nuevos resultados en corrutinas más rápido / menos código que lo que cabría hacer hoy. Es una gran presentación.

La propuesta funciones reanudables para C ++ se puede encontrar aquí .

Bueno, para un ejemplo tan trivial como eso, el único problema que veo es que no se especifica std::type_info::hash_code() constexpr. Creo que una aplicación conforme todavía podía hacerlo así, y apoyar esto. De todos modos el problema real es la obtención de identificadores únicos, por lo que podría ser otra solución. (Obviamente me prestó su construcción "interruptor maestro", gracias.)

#define YIELD(X) do { \
    constexpr size_t local_state = typeid([](){}).hash_code(); \
    return (X); state = local_state; case local_state: ; } \
while (0)

Uso:

struct GeneratedFibonacci {
    size_t state;
    int a, b;

    GeneratedFibonacci() : state (0), a (0), b (1) {}

    int operator()() {
        switch (state) {
        case 0:
            while (true) {
                YIELD( a );
                int c = a + b;
                a = b;
                b = c;
            }
        }
    }
}

Hmm, ellos también necesitan garantías de que el hash no es 0. No hay problema allí. Y una macro DONE es fácil de implementar.


El problema real es lo que sucede cuando regrese de un ámbito con objetos locales. No hay esperanza de salvar de un marco de pila en un lenguaje basado en C. La solución es utilizar un co-rutina real, y C ++ 0x hace directamente dirección que con hilos y futuros.

Considere este generador / corrutina:

void ReadWords() {
    ifstream f( "input.txt" );

    while ( f ) {
        string s;
        f >> s;
        yield s;
    }
}

Si se utiliza un truco similar para yield, f se destruye en la primera yield, y es ilegal para continuar el bucle después de ella, porque no se puede goto o switch más allá de una definición de objeto no POD.

ha habido varios implementación de corrutinas como bibliotecas de espacio de usuario. Sin embargo, y aquí está el acuerdo, esas realizaciones se basan en datos no estándar. Por ejemplo, en ninguna parte en el estándar de C ++ se especifica cómo se mantienen los marcos de pila. La mayoría de las implementaciones sólo tienes que copiar la pila porque es la forma más implementaciones de C ++ de trabajo

respecto a las normas, c ++ podría haber ayudado apoyo corrutina mediante la mejora de la especificación de los marcos de pila.

En realidad 'añadir' a la lengua no suena una idea buena para mí, porque habría que seguir con una aplicación suficientemente buena para la mayoría de los casos que es totalmente dependiente del compilador. Para los casos donde el uso de materias co-rutina, esto no es aceptable de todos modos

de acuerdo con @Potatoswatter primero.

Para apoyar corrutina no es lo mismo que el apoyo a lambdas y no la simple transformación como jugado con dispositivo de Duff.

Es necesario completa corrutinas asimétricas (stackful ) para funcionar como generadores en Python. La implementación de Simon Tatham y Chris' son a la vez sin pérdida de velocidad, mientras que Boost.Coroutine es una stackfull pesar de que es pesado.

Por desgracia, C ++ 11 todavía no tienen yield para corrutinas aún, tal C ++ 1a;)

PD: Si realmente te gusta generadores de estilo de Python, echar un vistazo a este .

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top