CPython

CPython/ 평가루프

25G 2023. 1. 24. 23:39

컴파일된 코드 객체는 바이트코드로 표현된 이산 연산 리스트를 포함한다.

코드 객체는 입력이 없으면 실행할 수 없다. 파이썬에서 입려은 전역 지역 변수의 형태를 취한다.

 

Cpython에서 코드는 평가루프라는 중심 루프에서 실행된다. cpython 인터프리터는 마셜링된 .pyc파일이나 컴파일러가 전달한 코드 객체를 평가하고 실행한다.

평가루프는 스택프레임 기반 시스템을 사용해바이트코드 명령을 실행한다.

모든 함수 호출은 스택프레임을 가지며 호출 순서에 따라 쌓인다. 만약 처리되지 않은 예외가 발생하면 스택프레임이 콘솔에 뜨는 것을 볼 수 있다. 

 

평가 루프와 관련된 소스 파일

Python/ceval.c

Python/ceval-gil.h

 

  • 평가 루프는 코드 객체를 입력 받아일련의 프레임 객체를 변환한다.
  • 인터프리터는 최소 한개의 스레드를 가진다.
  • 각 스레드는 스레드 상태를 가진다.
  • 프레임 객체는 프레임 스택에서 실행된다.
  • 값 스택에서 변수를 참조 할 수 있다.

 

스레드 상태 생성하기

 

프레임을 실행하려면 스레드에 연결해야 한다. CPython은 한 인터프리터 내에서 동시에 여러 스레드를 실행할 수 있다. 인터프리터 상태는 인터프리터 내에서 동시에 여러 스레드를 실행할 수 있다. 인터프리터 내의 스레드들을 연결 리스트로 관리한다. Cpython은 최소 한 개 이상의 스레드를 실행하며 스레드는 스레드 상태를 가진다.

 

스레드 상태

 

  • 고유 식별자
  • 다른 스레드 상태와 연결된 연결 리스트
  • 스레드를 스폰한 인터프리터의 상태
  • 현재 실행 중이 프레임
  • 현재 재귀 깊이
  • 선택적 추적 함수들
  • 현제 처리중인 예외
  • 현제 처리중인 비동기 예외
  • 여러 예외가 발생할 때의 예외 스택
  • GIL 카운터
  • 비동기 제너레이터 카운터

 

스레드 상태에 대한 소스 코드는 여러 파일에 분산되어 있다.

Python/thread.c

Include/threadstate.h

Include/pystate.h

Include/pythread.h

Include/cpython/pystate.h

 

 

프레임 객체 생성하기

 

컴파일된 코드 객체는 프레임 객체에 삽입된다. 파이썬 타입인 프레임 객체는 C와 파이썬 코드 양쪽에서 참조 할 수 있다.

프레임 객체는 코드 객체의 명령을 실행하는데 필요한 런타임 데이터를 포함한다. 런타임 데이터는 전역-지역변수, 내장모듈 등이 포함된다.

 

프레임 객체 타입 PyFrameObject

프래임 객체와 관련된 소스 파일

- Objects/frameobject.c

- Include/frameobject.h

 

프레임 객체 초기화 API

프레임 객체를 초기화 하는 API인 PyEval_EvalCode()는 코드 객체를 평가하기 위한 진입점이다. PyEvalCode()는 내부함수 _PyEval_EvalCode()를 감싸는 래퍼 함수.

 

_PyEval_EvalCode()의 인자

  • tstate: 코드를 평가할 스레드의 상태를 가리키는 PyThreadState *
  • _co: 프레임 객체에 삽입할 코드를 담는 PyCodeObject *
  • globals: 변수 이름을 기로 사용하는 PyObject* (dict)
  • lovals: 변수 이름을 키로 사용하는 PyObject* (dict)

_PyFrame_New_NoTrack() 호출은 새 프래임을 생성한다. 이 API는 PyFrame_New() C API로 공개 되어있다.

새프레임 생성 프로세스

  1. 프레임의 f_back 프로퍼티를 스레드 상태의 마지막 프레임으로 설정
  2. f_builtins 프로퍼티를 설정하고 PyModule_GetDict()로 buitins 모듈에서 내장 함수들을 불러온다.
  3. f_code프로퍼티에 빈 값 스택을 설정한다
  4. f_valuestack 프로퍼티에 빈 값 스택을 설정
  5. f_stackpop에 f_caluestact을 가리키는 포인터를 설정
  6. 전역 이름 공간 프로퍼티인 f_globals에 인자로 받은 globals를 설정
  7. 지역 이름 공간 프로퍼티인 f_lovals에 새 딕셔너리를 설정
  8. 트레이스벡에 줄 번호를 표시하기 위해 f_lineno를 코드 객체의 co_firstlineno로 설정한다.
  9. 나머지 프로퍼티는 기본값으로 설정한다.

 

코어평가 루프는 컴파일된 파이썬 코드 그리고 기반이 된는 c확장 모듈과 라이브러리, 시스템 호출간의 인터페이스다.

Cpython 인터프리터는 코어 평가 루프 이외에도 병령적이든 동시적이든 여러 루프를 동시에 실행할 수 있다.

Cpython은 여러 프레임을 다수의 평가루프에서 실행할 수 있다.