如何在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 被视为文件 I/O,或者因为 dll 本身执行文件 I/0。因此,循环在 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)
我希望这对某人有帮助!
I have a python program that uses ctypes to call a dll function to which I pass a pointer. It is supposed to write data continuously to that pointer and I want my program to loop and read the pointers contents. A rough template would look like:
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(), in my specific case, is written in C and opens a file and decodes it, running the data as a stream into a character array.
The problem is that I can't use the regular threading module in python since the thread holds the GIL either since reading the dll is considered file I/O or because the dll itself does file I/0. Therefore, the loop does not run until dostuff() is complete. What is the reason it blocks (will dll calls always block?) and how can I get around this?
EDIT:
----------SOLVED----------------------
As samplebias points out below, ctypes releases the GIL lock. I discovered that the blocking issue in my program was that I was running a queue:
The code looked a bit like this
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)
The program was blocking because queue.get() blocks when the queue is empty, until something goes inside! Of course, since I didn't thread the dll call alone, it finished before I pushed the pointers results to the queue. The solution looks a bit like this:
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)
I hope this helps someone!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这绝对可以使用线程来实现,因为 ctypes 在调用 C 函数之前释放 GIL。这使得(除其他外)C 例程能够回调到 Python 代码而不会造成死锁。
您将遇到的唯一问题是如何向 DLL 发出信号以停止传递数据,但也有一些方法可以解决这个问题,例如传递第二个指针作为指示何时返回的标志。
这是一个与您的问题相符的工作示例,例如,GIL 被发布,Python 和 C 代码同时运行:
共享对象:test.c
编译它:
Python 代码: test.py
输出
This can definitely work using threading, since
ctypes
releases the GIL before calling a C function. This enables (among other things) the C routine to call back into Python code without creating a deadlock.About the only problem you'll encounter is how to signal to the DLL to stop delivering data, but there are ways to solve that as well, e.g. passing a 2nd pointer as a flag indicating when to return, for example.
Here is a working example along the lines of your question, e.g. the GIL is released and the Python and C code run concurrently:
Shared object: test.c
Compile it:
Python code: test.py
Output
Python 的 multiprocessing 模块具有与线程类似的接口,但没有 GIL。
Python's multiprocessing module has an interface similar to threading's but with no GIL.