免责声明:我对多线程非常糟糕,所以我完全有可能做错了。
我在Python中编写了一个非常基本的光线跟踪器,我正在寻找可能加速它的方法。多线程似乎是一种选择,所以我决定尝试一下。但是,虽然原始脚本需要大约85秒来处理我的示例场景,但多线程脚本最终需要大约125秒,这看起来非常不直观。
这是原始的样子(我不打算在这里复制绘图逻辑和内容。如果有人认为需要找出问题,我会继续把它放回去):
def getPixelColor(x, y, scene):
<some raytracing code>
def draw(outputFile, scene):
<some file handling code>
for y in range(scene.getHeight()):
for x in range(scene.getWidth()):
pixelColor = getPixelColor(x, y, scene)
<write pixelColor to image file>
if __name__ == "__main__":
scene = readScene()
draw(scene)
这是多线程版本:
import threading
import Queue
q = Queue.Queue()
pixelDict = dict()
class DrawThread(threading.Thread):
def __init__(self, scene):
self.scene = scene
threading.Thread.__init__(self)
def run(self):
while True:
try:
n, x, y = q.get_nowait()
except Queue.Empty:
break
pixelDict[n] = getPixelColor(x, y, self.scene)
q.task_done()
def getPixelColor(x, y, scene):
<some raytracing code>
def draw(outputFile, scene):
<some file handling code>
n = 0
work_threads = 4
for y in range(scene.getHeight()):
for x in range(scene.getWidth()):
q.put_nowait((n, x, y))
n += 1
for i in range(work_threads):
t = DrawThread(scene)
t.start()
q.join()
for i in range(n)
pixelColor = pixelDict[i]
<write pixelColor to image file>
if __name__ == "__main__":
scene = readScene()
draw(scene)
有什么明显的东西我做错了吗?或者我错误地假设多线程会对这样的进程加速?
答案 0 :(得分:8)
我怀疑Python Global Interpreter Lock会阻止您的代码同时在两个线程中运行。
What is a global interpreter lock (GIL)?
显然,您希望利用多个CPU。你能跨进程而不是线程分割光线跟踪吗?
多线程版本显然会做更多的“工作”,所以我希望它在单个CPU上更慢。
我也不喜欢继承Thread
,只是用t = Thread(target=myfunc); t.run()
构建一个新线程
答案 1 :(得分:2)
要直接回答您的问题,Python线程不会提高性能,GIL实际上可能会使其更糟。
在更大的方案中,我喜欢python和光线追踪,但你永远不应该将它们结合起来。 Python光线跟踪器的速度至少比C或同等版本的C ++版本慢2个数量级。
因此,从Python程序员的角度来看,你的问题很有意思,从光线追踪的角度来看,这很有趣。
答案 2 :(得分:2)
我怀疑你可能有两个问题中的一个(或两个都是)。首先,我同意Joe的观点,Global Interpreter Lock可能会导致问题。
其次,看起来你在这个过程中经常编写一个文件(特别是在内部循环的每次迭代时都是非线程版本)。您是否可能在磁盘上有时间限制而不是CPU?如果是这样,那么当您添加线程时,您增加了管理线程的开销,而没有解决实际的瓶颈问题。在优化时,请确保首先确定您的瓶颈,这样您至少可以猜测在解决这些问题时哪些可能会给您带来最大的好处。