2013-04-17 7 views
0

요청을 받아들이고 일부 Python을 실행해야하는 서버 응용 프로그램이 있는데 그 중 일부는 C 기반 확장 DLL로 호출됩니다. 전체 요청 중에 GIL을 완전히 잠그면 모든 것이 잘 동작합니다. 하지만 더 많은 요청을 처리 할 수 ​​있도록 long-ish 작업이 진행 중일 때 C 기반 확장 DLL에서이 파일을 릴리스하고 싶습니다. 이것은 지금까지 내 접근 방식입니다 :Python GIL, C 확장 및 증가 형 (Python 3.2)

위의 모든 단계는 단일 스레드 (시스템에 많은 유사한 스레드가 있음)입니다.

위의 호출 순서는 항상 파이썬에서 (H) 깊은 곳에서 예외를 던집니다 (스택 추적에서 알 수없는 것 같습니다). 그러나 (B)에서 PyGILState_Ensure를 추가 호출하여 (E)와 (F)의 호출이 아무 것도하지 않게하면 모든 것이 완벽하게 실행됩니다.

누군가 내가 잘못하고있는 것을 이해하도록 도와 줄 수 있습니까? 다른 작업이 진행될 수 있도록 길어진 작업 중에 GIL을 릴리스하고 싶습니다.

+0

당신이 각 단계에 적절한'PyGILState_STATE'을 사용하고 있는지 있습니까? 즉,'B'에서'E'에있는 것을 전달해야하고,'G'의 값을'J'에 전달하는 다른 변수에 저장해야합니다. (또는'E'와'G'를'Py_BEGIN_ALLOW_THREADS' /'Py_END_ALLOW_THREADS' 쌍으로 만들 수 있습니다.) – abarnert

+0

또한 의사 코드 대신 [SSCCE] (http://sscce.org)를 제공 할 수 있습니까? – abarnert

+0

스레드마다 PyGILState_STATE 값을 사용하고 있으므로 B, E, G 및 J에 대해 동일한 변수가됩니다. – DougN

답변

2

먼저 B와 J, E와 G의 더 순진한 일치 검색보다는 B와 E 및 G와 J의 PyGILState_Ensure/PyGILState_Release 쌍을 일치시켜야합니다. , E 단계는 초기화되지 않은 상태를 해제하여 인터프리터의 내부 상태 정보를 손상시킵니다.)

하지만 문제가없는 단일 상태를 사용하고 있습니다. (나는 이것이 법적 실제로 모르겠지만, 나는 그것이 CPython과의 모든 버전과 안전 확신하고 순서가 일을 얻을 수있는 방법은 확실히 없습니다.)


불행하게도, 이것은이있다 다른 문제입니다. PyGILState_Release 문서가 말하는대로 :

이전에 획득 한 모든 리소스를 해제하십시오. 는 해당 PyGILState_Ensure() 호출하기 전에이었다으로이 호출 후, 파이썬의 상태는 보호하지 않는 한 당신은 (A Release 이후 Ensure에 걸쳐있는 통역 자원을 수행 할 수없는, 즉

... 동일합니다 물론 바깥 쪽은 Ensure이지만 실제로는 아무 것도 공개하지 않습니다.)

ReleasePyRun_String으로 보장되는 상태가되면 나머지는 PyRun_String 통화가 무효화됩니다. 중간에 새로 인수 한 국가로 전환하는 것은 도움이되지 않습니다.


는하지만 난 당신이 처음에 Ensure/Release 불필요하게 남용하는 것 같아요. 인터프리터에 스레드를 등록하고 등록을 취소하고 다시 등록한 다음 다시 등록을 취소 할 필요는 없습니다. 동일한 스레드 내에서 GIL을 릴리스하고 다시 획득하기 만하면됩니다. 그게 Py_BEGIN_ALLOW_THREADSPy_END_ALLOW_THREADS입니다.

PyGILState_Ensure에 대한 설명서는 말하기를 : 스레드의 상태가 릴리스하기 전에 이전 상태로 복원으로

일반적으로, 다른 스레드 관련 API에서

만큼 PyGILState_Ensure()PyGILState_Release() 호출 사이에 사용할 수있다() . 예를 들어, Py_BEGIN_ALLOW_THREADSPy_END_ALLOW_THREADS 매크로를 정상적으로 사용할 수 있습니다.

그래서 :

PyGILState_STATE state; 

B. state = PyGILState_Ensure(); 
    ... 
E.    Py_BEGIN_ALLOW_THREADS 
F.     Do long-ish processing 
G.    Py_END_ALLOW_THREADS 
    ... 
J. PyGILState_Release(state); 
+0

어쩌면 ALLOW_THREADS가 가장 좋은 방법 일 것입니다. 나는 중요한 부분에 너무 익숙해있어 필요할 때 잠그는 것이 가장 좋았을 것 같았고 필요가 없다고 확신 할 때 잠금을 해제하지 않았습니다. – DougN

+0

@DougN은 : 정말 동일하지 비록, 그것을 이런 식으로 생각 : 당신은'할 LeaveCriticalSection (&cs); 된 DeleteCriticalSection (&cs); ... InitializeCriticalSection (&cs); EnterCriticalSection 않을 것 (&cs);을'그냥'Leave' /'Enter' 부품을 원하는 경우 , 맞지? – abarnert

+0

아, 그게 전구가 필요해! 고마워! – DougN