lenguaje - python tutorial
¿Cómo funcionan los greenlets? (2)
Cuando se ejecuta un programa de Python, tienes esencialmente dos piezas de código que se ejecutan bajo el capó.
Primero, el código C del intérprete CPython se ejecuta y usa la pila C estándar para guardar sus cuadros de pila internos. Segundo, el código de bytes real interpretado por python que no usa la pila C, sino que utiliza el montón para guardar sus cuadros de pila. Un greenlet es solo un código estándar de Python y por lo tanto se comporta de manera idéntica.
Ahora, en una aplicación típica de microtornillados, tendrías miles, si no millones, de microtornillos (greenlets) cambiando por todos lados. Cada conmutador es esencialmente equivalente a una llamada de función con un retorno diferido (por así decirlo) y por lo tanto utilizará un poco de pila. El problema es que la pila C del intérprete tarde o temprano llegará a un desbordamiento de pila. Esto es exactamente a lo que apuntaba la extensión greenlet, está diseñado para mover partes de la pila de un lado a otro desde el montón para evitar este problema.
Como saben, hay tres eventos fundamentales con greenlets, un engendro, un cambio y un retorno, así que analicemos esos a su vez:
A) un engendro
El greenlet recién generado está asociado con su propia dirección base en la pila (donde estamos actualmente). Aparte de eso, no pasa nada especial. El código de Python del greenlet recién generado utiliza el montón de manera normal y el intérprete continúa usando el C-stack como de costumbre.
B) un interruptor
Cuando se cambia a un greenlet de un greenlet de conmutación, la parte relevante de la pila C (comenzando desde la dirección base del greenlet de conmutación) se copia al montón. El área de pila C copiada se libera y los datos de pila guardados previamente del intérprete de greenlet conmutado se copian del montón al área de pila C recién liberada. El código de python del greenlet conmutado continúa utilizando el montón de forma normal. Por supuesto, el código de extensión hace un seguimiento de todo esto (qué sección del montón va a qué greenlet y así sucesivamente).
C) una devolución
La pila no ha sido tocada y el recolector de basura Python libera el área del montón del greenlet que regresa.
Básicamente, aquí se encuentran muchos más detalles y explicaciones 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. .
¿Cómo se implementan los greenlets ? Python usa la pila C para el intérprete y asigna montones de tramas de pila de Python, pero más allá de eso, ¿cómo asigna / intercambia pilas, cómo se enlaza con el intérprete y los mecanismos de llamada de función, y cómo interactúa esto con las extensiones C? (Cualquier peculiaridades)?
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 los aspectos internos de CPython pero que está muy familiarizado con la programación de sistemas de bajo nivel, C, hilos, eventos, hilos de programación / cooperativos, programación del núcleo, etc.
(Algunos puntos de datos: no usan ucontext.h y hacen 2x memcpy, alloc y free en cada cambio de contexto ).
Si obtiene y estudia las sources de greenlet, verá en la parte superior de greenlet.c
un comentario largo que comienza en la línea 16 con el siguiente resumen ...:
Un PyGreenlet es un rango de direcciones de pila C que debe guardarse y restaurarse de tal manera que el rango completo de la pila contenga datos válidos cuando lo cambiemos.
y continúa en la línea 82, que resume exactamente lo que estás preguntando. ¿Has estudiado estas líneas (y las siguientes 1000+ implementándolas; -) ...? No veo una manera de reducir aún más estas 66 líneas mientras aún tiene sentido, ni ningún valor agregado al copiarlas y pegarlas aquí.
Básicamente, verá que no hay un verdadero "enganche" del que hablar (la pila de nivel C se cambia de un lado a otro "por debajo de la nariz del intérprete", por así decirlo), excepto por las delicadas interacciones con el estado del hilo en el código de múltiples hilos. , y el guardar y restaurar el estado de un greenlet desde / hacia la pila se basa en memcpy
llamadas memcpy
más algunas llamadas al administrador de memoria de Python para asignar / reasignar y liberar espacio proveniente de, o volver a, la pila. Las tres funciones en la línea 227-295 manejan el trabajo duro, y están envueltas en un par de macros C al 298-310 "para simplificar el mantenimiento", como se indica en el comentario.
La interfaz a través de la cual otras extensiones C pueden interactuar con la extensión greenlet se implementa en las líneas 956-1045, y se expone a través de la "API CObject" (a través de greenlet.h
, por supuesto) documentada here .