如何在Python中并行调用dll函数
我有一个用Python写的程序,它使用ctypes来调用一个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()是用C语言写的,它打开一个文件并解码,然后把数据作为流写入一个字符数组中。
问题是,我不能使用Python的常规线程模块,因为线程会持有全局解释器锁(GIL),这可能是因为读取dll被认为是文件输入输出,或者因为dll本身进行文件输入输出。因此,循环在dostuff()完成之前不会运行。造成阻塞的原因是什么(dll调用总是会阻塞吗?),我该如何解决这个问题呢?
编辑: ----------已解决---------------------- 正如samplebias在下面指出的,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)
希望这对某些人有帮助!
2 个回答
Python的 multiprocessing 模块的使用方式和线程(threading)模块很像,但它没有全局解释器锁(GIL)。
这确实可以通过线程来实现,因为 ctypes
在调用 C 函数之前会释放全局解释器锁(GIL)。这意味着 C 代码可以在不造成死锁的情况下调用 Python 代码。
你可能遇到的唯一问题是如何告诉 DLL 停止发送数据,不过这也有解决办法,比如可以传递一个第二个指针作为标志,指示何时返回。
下面是一个符合你问题的工作示例,比如说 GIL 被释放,Python 和 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
Python 代码: 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 ... ...