최근에는 Python을 사용하여 웹 프로그램을 개발하고 있으며 항상 fastcgi 모드를 사용하고 있습니다. 그런 다음 요청 처리를 위해 각 프로세스에서 여러 스레드가 시작됩니다. 여기서 한 가지 문제는 각 요청의 응답 시간을 보장해야 한다는 것입니다. 매우 짧습니다. 그렇지 않으면 요청이 너무 느린 경우 어떤 스레드도 요청에 응답할 수 없기 때문에 서버는 서비스를 거부합니다. 일반적으로 우리 서비스는 온라인 상태가 되면 성능 테스트를 거치므로 정상적인 경우에는 큰 문제가 없습니다. 하지만 모든 시나리오를 테스트하는 것은 불가능합니다. 일단 나타나면 사용자가 응답하지 않고 오랜 시간을 기다려야 합니다. 그래서 일부 부분을 사용할 수 없게 되어 나중에 Python에서 코루틴과 그린렛으로 전환했습니다. 저는 그 구현 메커니즘을 간단하게 이해하고 있습니다.
각 Greenlet은 . >
typedef struct _greenlet { PyObject_HEAD char* stack_start; char* stack_stop; char* stack_copy; intptr_t stack_saved; struct _greenlet* stack_prev; struct _greenlet* parent; PyObject* run_info; struct _frame* top_frame; int recursion_depth; PyObject* weakreflist; PyObject* exc_type; PyObject* exc_value; PyObject* exc_traceback; PyObject* dict; } PyGreenlet;각 Greenlet은 실제로 함수이며 이 함수가 실행될 때 정보를 저장합니다. 함수의 경우 컨텍스트는 동일한 프로세스의 모든 Greenlet이 할당한 공통 사용자 스택을 공유합니다. 따라서 충돌하지 않는 스택 데이터가 있는 Greenlet만 이 글로벌 스택을 동시에 사용할 수 있습니다. 현재 스택에 있는 Greenlet의 경우, 겹쳐진 Greenlet의 스택 데이터를 힙에 임시 저장해야 하며, 저장된 위치는 stack_copy 및 stack_saved를 통해 기록되므로 스택의 stack_stop 및 stack_start 위치를 힙 백에서 복사할 수 있습니다. 그렇지 않으면 스택 데이터가 파괴됩니다. 따라서 애플리케이션에서 생성된 이러한 그린렛은 데이터를 힙에 지속적으로 복사하거나 힙에서 스택으로 복사하는 방식으로 IO에 코루틴을 사용하는 것이 정말 편리합니다. -type 애플리케이션.
다음은 greenlet.c의 간단한 스택 공간 모델입니다.
A PyGreenlet is a range of C stack addresses that must be saved and restored in such a way that the full range of the stack contains valid data when we switch to it. Stack layout for a greenlet: | ^^^ | | older data | | | stack_stop . |_______________| . | | . | greenlet data | . | in stack | . * |_______________| . . _____________ stack_copy + stack_saved . | | | | . | data | |greenlet data| . | unrelated | | saved | . | to | | in heap | stack_start . | this | . . |_____________| stack_copy | greenlet | | | | newer data | | vvv |다음은 간단한 greenlet 코드입니다.
from greenlet import greenlet def test1(): print 12 gr2.switch() print 34 def test2(): print 56 gr1.switch() print 78 gr1 = greenlet(test1) gr2 = greenlet(test2) gr1.switch()