2011-04-22 4 views
3

ctypes를 사용하여 포인터를 전달하는 dll 함수를 호출하는 Python 프로그램이 있습니다. 그 포인터에 계속적으로 데이터를 쓰는 것으로 가정하고 프로그램이 포인터 내용을 반복하고 읽길 원합니다. 내 특정한 경우에, C로 작성과 문자 배열에 스트림으로 데이터를 실행하고, 파일을 열고 그것을 디코딩,Python에서 dll 함수를 병렬로 호출하는 방법

from ctypes import * 
import copy 
lib = cdll.lib 
pointer = c_char_p(" "*100) #however large a buffer I need 
#thread this 
lib.dostuff(pointer) 
#end thread 
while True: 
    data = pointer.value 
    print data 

dostuff() : 거친 템플릿과 같을 것이다.

문제는 파이썬에서 일반 스레드 모듈을 사용할 수 없다는 것입니다. 왜냐하면 스레드가 GIL을 보유하고 있기 때문에 dll을 읽는 것이 파일 I/O로 간주되거나 dll 자체가 I/O 파일을 수행하기 때문입니다. 따라서 dostuff()가 완료 될 때까지 루프가 실행되지 않습니다. 블록하는 이유는 무엇입니까 (dll 호출은 항상 차단됩니까?) 어떻게이 문제를 해결할 수 있습니까?

편집 : ---------- 솔리드 ---------------------- 샘플 바이어스가 아래에서 지적하므로 ctypes는 GIL 자물쇠. 내 프로그램에서 차단 문제는 내가 대기열을 실행하는 것을 것을 발견 : 코드는 다음과

import Queue 
from threading import Thread 

queue = Queue() 

def runthread(): 
    lib.dostuff(pointer) 
    while True: 
     queue.put(pointer.value) 

thread = Thread(target=runthread) 
thread.start() 
while True: 
    data = queue.get() 
    dostuffwithdata(data) 

프로그램 같은 비트가 차단 된 모습 때문에 큐가 될 때까지 비어 queue.get() 블록 뭔가가 안에 들어간다! 물론, dll 호출을 단독으로 처리하지 않았으므로 포인터 결과를 대기열로 보내기 전에 처리가 완료되었습니다. 해결책은 다음과 같이 보입니다.

import Queue 
from threading import Thread 

queue = Queue() 

def runthread(): 
    q = Thread(target=lib.dostuff, args=(pointer,)) 
    q.start() 
    while True: 
     queue.put(pointer.value) 

thread = Thread(target=runthread) 
thread.start() 
while True: 
    data = queue.get() 
    dostuffwithdata(data) 

이 정보가 도움이되기를 바랍니다.

+0

당신은'lib.dostuff을 포함 할 수 있습니다()', 그것은 막고 코드이기 때문에. – nmichaels

+0

exploing dostuff()에 조금 더 편집 됨 : P –

답변

7

ctypes은 C 함수를 호출하기 전에 GIL을 해제하므로이 작업은 확실히 스레딩을 사용하여 작동 할 수 있습니다. 이렇게하면 C 루틴이 (교착 상태를 만들지 않고) 파이썬 코드를 다시 호출 할 수 있습니다.

발생할 수있는 유일한 문제는 데이터 전달을 중단하기 위해 DLL에 신호를 보내는 방법이지만 문제를 해결할 수있는 방법이 있습니다. 예를 들어, 리턴 할시기를 나타내는 플래그로서 제 2 포인터를 전달한다.

다음은 질문의 라인을 따라 작업 한 예입니다. GIL로 해제하고, 파이썬과 C 코드가 동시에 실행됩니다 :

공유 객체 : TEST.C

#include <stdint.h> 
#include <stdio.h> 

void 
dostuff(uint64_t *ptr) 
{ 
    while (1) 
     (*ptr)++; 
} 

그것을 컴파일

% gcc -shared -g -o test.so test.c -fPIC 

파이썬 코드 : test.py

import ctypes 
import sys 
import time 
import threading 

lib = ctypes.cdll.LoadLibrary('./test.so') 
val = ctypes.c_uint64(0) 

def loop(): 
    lib.dostuff(ctypes.byref(val)) 

t1 = threading.Thread(target=loop) 
t1.start() 

for i in range(1000): 
    sys.stdout.write('%s ' % val.value) 
    sys.stdout.flush() 
    time.sleep(0.05) 

출력

% python test.py 
0 24664442 48388062 71628820 94834416 118004961 141095893 164936784 ... ... 
+0

이것은 확실히 작동하지만 내 문제는 해결되지 않습니다. 내 C 코드를 자세히 살펴보고 문제의 원인을 확인해야합니다. dll의 콘솔 출력이 잠금을 재개 할 수 있습니까? –

+0

다른 dll에 대한 자세한 내용을 알지 못하면 어떻게하면 메인 스레드에서 실행에 영향을 줄 수 있는지 말할 수 없습니다. 최소한 실행이 dll 함수를 시작할 때 ctypes/GIL을 배제 할 수 있습니다. – samplebias

+0

+1 답답한 답변 : 설명, 소스, 컴파일 단계 및 실행 결과. – coffeetocode

1

파이썬의 multiprocessing 모듈에는 스레딩과 유사하지만 GIL이없는 인터페이스가 있습니다.

+0

소리가 좋았습니다. 시도해 볼 것이지만, 가능한 경우 다중 처리가없는 Python 2.5에서이 작업을 수행하고 싶습니다. –

관련 문제