2010-07-28 24 views
47

¿Cómo se implementa greenlets? Python usa la pila C para el intérprete y asigna montones de montones de Python, pero más allá de eso, ¿cómo asigna/intercambia pilas, cómo se engancha en los mecanismos de intérprete y llamada de función, y cómo interactúa esto con las extensiones C? (Cualquier peculiaridad)?¿Cómo funcionan los greenlets?

Hay algunos comentarios en la parte superior de greenlet.c en la fuente, pero son un poco opacos. FWIW Vengo desde la perspectiva de alguien que no está familiarizado con las funciones internas de CPython, pero está muy familiarizado con la programación de sistemas de bajo nivel, C, hilos, eventos, coroutines/hilos cooperativos, programación kernel, etc.

(Algunos datos puntos: que don't use ucontext.h y do 2x memcpy, alloc, and free on every context switch)

Respuesta

28

Si llegar y estudio de la sources greenlet, verá en la parte superior de greenlet.c un comentario largo que comienza en la línea 16 con el siguiente resumen ...:.

A PyGreenlet es un rango de C stack direcciones que deben se guardará y se restaurará de tal manera que el rango completo de la pila contiene datos válidos cuando lo cambiemos.

y continúa en la línea 82, que resume exactamente lo que pregunta. ¿Has estudiado estas líneas (y las siguientes 1000+ implementandolas; -) ...? No veo la manera de exprimir aún más estas 66 líneas mientras sigo teniendo sentido, ni ningún valor añadido al copiarlas y pegarlas aquí.

Básicamente, verás que no hay un "enganche" real para hablar (la pila de nivel C se mueve hacia adelante y hacia atrás "por debajo del intérprete", por así decirlo) excepto por las delicadas interacciones con el estado del hilo en código de subprocesos múltiples, y el guardado y restauración del estado de un greenlet desde/hacia la pila se basa en llamadas memcpy más algunas llamadas al administrador de memoria de Python para asignar/reasignar y liberar espacio proveniente de la pila o regresando a ella. Las tres funciones en la línea 227-295 manejan el trabajo gruñido, y están envueltas en un par de macros C a 298-310 "para simplificar el mantenimiento", como dice el comentario allí.

La interfaz a través del cual otras extensiones C pueden interactuar con la extensión greenlet se implementa en las líneas de 956-1045, y expuesta a través de la "API CObject" (a través de greenlet.h, por supuesto) documentaron here.

+3

Ese bloque de comentarios me resulta confuso y realmente no responde mis preguntas. Solo esperaba un resumen/respuesta conciso y de alto nivel. Gracias por los punteros de todos modos, espero que sean útiles para otros (o para mí mismo cuando encuentre más tiempo para el buceo de origen). – Yang

+0

@Yang, esas 86 líneas ** son ** un resumen conciso y de alto nivel, alcanzando la mayoría de los aspectos más destacados de las 1410 líneas de código que juntas forman los archivos '.c' y' .h'! "Memcpy guarda las porciones de apilamiento en la memoria asignada y reasignada por el administrador de memoria de Python y restaurada por memcpy nuevamente en la pila (luego se libera la memoria de Python)" es aún más conciso y de nivel superior (pero ya lo dije todo) esto en mi respuesta!) pero obviamente falta algunos detalles importantes (ya que son dos líneas de texto, no 86 ;-). ¿Qué texto mágico esperas que se interponga y te haga feliz? –

+7

Para empezar: ¿qué es "datos de pila de Greenlet"? ¿Es solo la contabilidad para el greenlet? ¿O incluye realmente ciertos marcos de C stack? ¿Cuál es el "lugar correcto en la pila" de un punto verde? ¿Por qué siempre hay dos bloques de Greenlet/por qué el anterior está en montón? ¿Qué son los "datos no relacionados con este punto verde" debajo de los "datos de la pila de Greenlet"? Diff btwn "datos no relacionados" y "datos más nuevos"? Etc. Es una pequeña cantidad de C, pero también estoy ocupado y esto no está relacionado en absoluto con mi trabajo actual, solo por curiosidad. La pregunta simplemente estalló en mi cabeza. De nuevo, feliz de bucear más tarde una vez que encuentre el tiempo. – Yang

29

Cuando se ejecuta un programa python, tiene esencialmente dos piezas de código que se ejecutan bajo el capó.

En primer lugar, el código C del intérprete CPython se ejecuta y utiliza la pila C estándar para guardar sus estructuras internas de pila. En segundo lugar, el código de bytes interpretado por python real que no utiliza la pila C, sino que utiliza el montón para guardar sus marcos de pila. Un greenlet es solo un código python estándar y, por lo tanto, se comporta de forma idéntica.

Ahora en una aplicación microteñida típica, tendría miles o incluso millones de microthreads (greenlets) cambiando por todos lados. Cada interruptor es esencialmente equivalente a una llamada a función con un retorno diferido (por así decirlo) y por lo tanto usará un poco de pila. El problema es que la pila C del intérprete tarde o temprano golpeará un desbordamiento de la pila. Esto es exactamente a lo que apunta la extensión de greenlet, está diseñado para mover piezas de la pila hacia y desde el montón para evitar este problema.

Como saben, hay tres acontecimientos fundamentales con Verdecillo, un engendro, un interruptor y un retorno, por lo que vamos a ver los que a su vez:

A) Una freza

El recientemente greenlet generado se asocia con su propia dirección base en la pila (donde estamos actualmente). Aparte de eso, no sucede nada especial. El código python del greenlet recién generado usa el montón de una manera normal y el intérprete continúa usando el C-stack como de costumbre.

B) Un interruptor de

Cuando un greenlet se conmuta a partir de una greenlet de conmutación, la parte correspondiente de la C-pila (empezando por la dirección base de la greenlet switchng) se copia en el montón. El área copiada de C-stack se libera y el intérprete de Greenlet conmutado previamente guardado datos de pila se copia del montón al área C-stack recién liberada. El código python del greenlet conmutado continúa usando el montón de una manera normal. Por supuesto, el código de extensión realiza un seguimiento de todo esto (qué sección de pila va a qué punto de referencia, etc.).

C) A Return

La pila está intacto y el área montón de la greenlet volver es liberado por el recolector de pitón de basura.

Básicamente esto es todo, muchos más detalles y explicaciones se pueden encontrar en (http://www.stackless.com/pipermail/stackless-dev/2004-March/000022.html) o simplemente leyendo el código como se indica en la respuesta de Alex.