요약
- greenlet은 경량 스레드 일종으로 스택 기반의 context 전환을 사용해 실행 정보를 중간에 저장해 멈추고 다시 멈췄던 지점부터 다시 실행할 수 있다.
본문
-
greenlet: 스택 기반의 컨텍스트 전환을 구현한 경량 스레드
-
경량 스레드: context switching 비용이 적은 실행 단위
-
greenlet 구현(경량화 스레드, green thread)
typedef struct _greenlet {
PyObject_HEAD
struct _greenlet* parent;
void* stack_start;
void* stack_stop;
void* stack_copy;
intptr_t stack_saved;
char* stack_prev;
PyObject* run_info;
PyObject* weakreflist;
PyObject* dict;
PyObject* context;
} PyGreenlet;
- stack_start, stack_stop: 현재 스택 범위
- stack_copy: 비활성화시 스택 백업 저장
- parent: 전환 복귀 대상
- run_info: 현재 실행중인 스레드 정보
작업 전환
static PyGreenlet* g_current;
int g_switch(PyGreenlet* target) {
// 현재 스택 저장
save_stack(g_current);
// 대상 스택 복원
restore_stack(target);
g_current = target;
return 0;
}
void save_stack(PyGreenlet* g) {
char dummy;
g->stack_stop = &dummy; # 현재 스택 포인터의 위치를 stack_stop에 저장
size_t size = g->stack_start - g->stack_stop; # 현재 스택 크기
g->stack_copy = malloc(size); # size 만큼 동적 할당
memcpy(g->stack_copy, g->stack_stop, size); # 메모리 카피 상태 저장
g->stack_saved = size;
}
void restore_stack(PyGreenlet* g) {
memcpy(g->stack_stop, g->stack_copy, g->stack_saved);
}
왜 경량 스레드는 OS 스레드 보다 가볍지?
- os 스레드는 아래와 같은 over head가 존재함
- 컨텍스트 전환(유저 모드 → 커널 모드 전환) 으로 인한 인터럽트
- 전체 레지스터, 커널 스택 저장 필요
- 캐시 손실
- 스케줄러 오버헤드