2014-06-19 3 views
4

저는 파이썬을 C++ 플러그인에 임베드했습니다. 플러그인은 매 세션마다 알고리즘에 다른 데이터를 보낼 때마다 파이썬 알고리즘을 수십 번 호출합니다. 지금까지는 매우 좋은임베디드 파이썬 중지

그러나 문제가 있습니다 : 알고리즘은 해결하기 위해 몇 분이 걸릴 때가 있고 솔루션을 반환하는 경우가 종종 있습니다. 그 동안에는 조건이 변경되어 관련 솔루션과 관련성이 없어집니다. 그래서, 내가 원하는 것은 언제든지 알고리즘의 실행을 멈추고 다른 데이터 세트로 즉시 실행하는 것입니다.

는 여기에 지금까지 가지고 파이썬을 내장하기위한 C++ 코드입니다 :

void py_embed (void*data){ 


counter_thread=false; 

PyObject *pName, *pModule, *pDict, *pFunc; 

//To inform the interpreter about paths to Python run-time libraries 
Py_SetProgramName(arg->argv[0]); 

if(!gil_init){ 
    gil_init=1; 
    PyEval_InitThreads(); 
    PyEval_SaveThread(); 
} 
PyGILState_STATE gstate = PyGILState_Ensure(); 

// Build the name object 
pName = PyString_FromString(arg->argv[1]); 
if(!pName){ 
    textfile3<<"Can't build the object "<<endl; 
} 

// Load the module object 
pModule = PyImport_Import(pName); 
if(!pModule){ 
    textfile3<<"Can't import the module "<<endl; 
} 

// pDict is a borrowed reference 
pDict = PyModule_GetDict(pModule); 
if(!pDict){ 
    textfile3<<"Can't get the dict"<<endl; 
} 

// pFunc is also a borrowed reference 
pFunc = PyDict_GetItemString(pDict, arg->argv[2]); 
if(!pFunc || !PyCallable_Check(pFunc)){ 
    textfile3<<"Can't get the function"<<endl; 
} 

/*Call the algorithm and treat the data that is returned from it 
... 
... 
*/ 

// Clean up 
Py_XDECREF(pArgs2); 
Py_XDECREF(pValue2); 
Py_DECREF(pModule); 
Py_DECREF(pName); 

PyGILState_Release(gstate); 

counter_thread=true; 
_endthread(); 

};

편집 : 파이썬의 알고리즘 내 일하지 않고 나는 그것이

+0

이 알고리즘은 실행 작은 단계 (이상적으로 분해 될 수있다 C++ 코드는 다음과 같을 수 있습니다 : 'while (stillNeeded) performNextStep();' –

+0

아니요, 알고리즘은 제 일이 아니므로 변경해서는 안됩니다. –

답변

4

죄송 변경되지해야하지만, 당신의 선택은 짧다. 파이썬 코드 (ok, plugin - 옵션이 아님)를 변경하거나 다른 프로세스에서 실행할 수 있습니다 (사이에 멋진 ipc 포함). 그런 다음 시스템 api를 사용하여이를 지울 수 있습니다.

+0

올바르게 이해하고 있다면 제안은 다음과 같습니다. 스레드 대신 프로세스를 사용합니까? 또는 더 나은,'py_embed' 스레드를 프로세스에 넣고 싶을 때 그것을 죽일 수 있습니까? 파이썬/C API에서 주 스레드 나 다른 스레드 내에서 작업 스레드를 종료 할 수있는 옵션이 없다는 사실에 놀랐습니다 ... –

+3

@ JoãoPereira는 메모리의 알 수없는 부분에 액세스하는 동안 스레드를 종료합니다. 실제로 실행을 멈추지 만 응용 프로그램을 예측하기 힘든 국가로 남겨 둡니다. 파일 핸들이나 메모리가 누출되거나 힙을 손상시킬 수 있습니다 (힙에 메모리를 반환하는 중이고 일부 명령에서는 중지하는 경우) 또는 다른 유사한 작업 일 수 있습니다. OS는 해지 (프로세스)시 알려진 속성을 가진 캡슐을 제공하며 모든 랩퍼에 대해 성능 저하가 부과됩니다. – Yakk

+1

@ JoãoPereira, 그 (컨트롤) 계약 (그리고 참여 - 스레드 내에서 실행되는 파이썬 코드의 참여 - 예 : 등록해야합니다 -하지만 파이썬 측면에 손을 얻을 수 없다면, 당신은 속임수를 사용해야 해 그것을 처리합니다. – user430051

5

이것은 파이썬에 대한 간단한 지식과 파이썬 문서를 빠르게 읽는 것을 기반으로합니다.

PyThreadState_SetAsyncExc을 사용하면 실행중인 파이썬 스레드에 예외를 주입 할 수 있습니다.

일부 스레드에서 파이썬 인터프리터를 실행하십시오. 다른 스레드에서 PyGILState_STATE 다음 PyThreadState_SetAsyncExc 주 스레드로. (이것은 파이썬 인터프리터에게 2 번째 스레드에 대해 가르치기위한 선구자적인 작업이 필요할 수도 있습니다).

실행중인 파이썬 코드에 "catch alls"가 없으면 실행을 종료해야합니다.

파이썬 하위 해석기를 작성하는 코드를 살펴보면 이전 스크립트가 종료되는 동안 새 스크립트를 시작할 수 있습니다.

Py_AddPendingCall도 사용하고 싶지만 주변에는 충분한 경고가있을 수 있습니다.

+1

대부분의 "catch-alls"는 서브 클래스 Exception만을 잡아냅니다. 따라서 다른 baseclass (예 : SystemExit)를 사용하여 예외를 사용하여이를 피할 수 있습니다. https://docs.python.org/2/library/exceptions.html –

2

그래서 결국 해결책을 찾았습니다.

알고리즘을 실행중인 스레드를 종료하는 대신 (T1이라고 함) 해당 시간에 관련이있는 데이터 세트를 사용하여 또 다른 하나 -T2를 만듭니다. 모든 스레드에서

나는이 작업을 수행합니다

if(thisthread==thread_counter){ 
    /*save the solution and treat it */ 
} 
:
thread_counter+=1; //global variable 
int thisthread=thread_counter; 

및 파이썬에서 솔루션 후

는 T1이나 T2에서 하나, 난 그냥 가장 "최근"인 확인 주어진다

컴퓨터 작업의 조건은 분명히 최상의 솔루션이 아니지만 제 목적을 충족시킵니다.

나는이 문제에 대해 생각을 해 봤는데 도움들

+3

정말입니까? 이 솔루션에 대해 확실한가요? 스레드가 점점 더 많이 발생하는 상황에서 스레드 당 CPU 시간이 줄어들어 더 오래 기다려야 할 수도 있습니다. –

+0

사실,이 솔루션을 시험해 본 후 언젠가는 문제가 정확히 무엇인지 밝혀 냈습니다 ... 제안 된 해결책을 시도 할 때 –

2

주셔서 감사하고, 서브 통역사는 당신에게 하나 개의 가능한 솔루션 https://docs.python.org/2/c-api/init.html#sub-interpreter-support를 제공 할 수 있음을 동의합니다. 새로운 인터프리터를 만들고 기존 인터프리터를 종료 할 것을 지원합니다.버그 & 섹션에서는 아키텍처에 따라 문제가 나타날 수도 있고 그렇지 않을 수도있는 몇 가지 문제에 대해 설명합니다.

또 다른 가능한 해결책은 파이썬 multiprocessing 모듈을 사용하는 것입니다, 당신의 작업자 스레드 테스트에서 전역 변수 (time_to_die 같은). 그런 다음 부모로부터 GIL을 잡고 변수를 설정하고 GIL을 해제 한 다음 자식이 끝날 때까지 기다립니다.

그런데 또 다른 생각이 들렸습니다. 왜 fork()를 사용하지 않고, 파이썬 인터프리터를 자식에서 초기화하고, 부모가 파이썬 스레드가 끝날 때라고 결정하면, 그냥 죽여라. 이런 식으로 뭔가 :

void process() { 

    int pid = fork(); 
    if (pid) { 
     // in parent 
     sleep(60); 
     kill(pid, 9); 
     } 
    else{ 
     // in child 
     Py_Initialize(); 
     PyRun_SimpleString("# insert long running python calculation"); 
     } 
    } 

는 (이 예는 가정 * nix에서 스크립트, Windows에서, 대체 CreateProcess를을() 인 경우 /를 TerminateProcess는())

+0

새로운 하위 해석기가 모듈을 가져와야한다고 생각하기 때문에 제안 1이 좋지 않습니다. 다시, 그리고 그 시간이 좀 걸립니다 .. 다른 2 제안에 관해서는, 나는 (비록 그것이 아직 무엇인지 전혀 모르겠지만) 포크()가 더 좋아하지만 분명히 두 가지를 조사 할 것입니다. 지금까지 최고의 답변과 현상금을 수여했습니다 –

+0

그냥 한 가지, 저는 Windows에서이 CreateProcess() 작업을 쉽게 이해하지 못합니다. 당신의 예제를 리눅스에서 윈도우로 업데이트 할 수 있습니까? –

+0

CreateProcess는 부모 프로세스와 연결되어 있지 않은 자식 프로세스를 fork하는 win32 호출입니다. 다음은 간단한 예제입니다 : http://msdn.microsoft.com/en-us/library/windows/desktop/ms682512%28v=vs.85%29.aspx. 이 개념은 fork()와 동일하지만 Microsoft 호출에는 몇 가지 추가 옵션이 있습니다 (대부분은 NULL 일 수 있음). 새 자녀의 첫 번째 작업은 파이썬을 초기화하고 "할 일"입니다. 당신은 원한다면 언제든지 그것을 완전히 죽일 수 있습니다 - 완전히 안전하게. 그것은 당신이 그것을 죽이기로 선택할 때 부모에게 영향을주지 않습니다. – user590028

관련 문제