OS X 10.8上的PyCuda / Multiprocessing问题

时间:2013-02-05 23:43:17

标签: python cuda multiprocessing osx-mountain-lion pycuda

我正在开展一个项目,我将计算任务分配给多个python进程,每个进程都与自己的CUDA设备相关联。

当产生子进程时,我使用以下代码:

import pycuda.driver as cuda

class ComputeServer(object):
    def _init_workers(self):
        self.workers = []
        cuda.init()
        for device_id in range(cuda.Device.count()):
            print "initializing device {}".format(device_id)
            worker = CudaWorker(device_id)
            worker.start()
            self.workers.append(worker)

CudaWorker在另一个文件中定义如下:

from multiprocessing import Process
import pycuda.driver as cuda

class CudaWorker(Process):
    def __init__(self, device_id):
        Process.__init__(self)
        self.device_id = device_id

    def run(self):
        self._init_cuda_context()
        while True:
            # process requests here

    def _init_cuda_context(self):
        # the following line fails
        cuda.init()
        device = cuda.Device(self.device_id)
        self.cuda_context = device.make_context()

当我在Windows 7或Linux上运行此代码时,我没有任何问题。使用OSX 10.8.2,Cuda 5.0和PyCuda 2012.1在MacBook Pro上运行代码时出现以下错误:

Process CudaWorker-1:
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/process.py", line 258, in _bootstrap
    self.run()
  File "/Users/tombnorwood/pymodules/computeserver/worker.py", line 32, in run
    self._init_cuda_context()
  File "/Users/tombnorwood/pymodules/computeserver/worker.py", line 38, in _init_cuda_context
    cuda.init()
RuntimeError: cuInit failed: no device

运行PyCuda脚本没有问题,而不会在我的Mac上使用新进程。我只在产生新流程时遇到此问题。

之前有没有人遇到过这个问题?

1 个答案:

答案 0 :(得分:2)

根据我的经验,这实际上只是一个有根据的猜测,但我怀疑CUDA(或可能是PyCuda)的OS X实现依赖于fork之后无法安全使用的某些API,而linux实现没有。*由于multiprocessing的POSIX实现使用fork而没有exec来创建子进程,这可以解释为什么它在OS X上失败但在linux上失败。 (在Windows上, 没有fork,只有spawn等效,所以这不是问题。)

最简单的解决方案是放弃multiprocessing。如果CUDA和PyCUDA是线程安全的(我不知道它们是否是),并且你的代码不受CPU限制(只是受GPU限制),你可能只需要放入threading.Thread代替multiprocessing.Process并完成它。或者您可以考虑为multiprocessing提供类似API的其他并行处理库之一。 (有些人仅使用pp,因为它总是exec s ...)

然而,将multiprocessing升级到exec / spawn一个新的Python解释器然后做所有Windows风格而不是POSIX风格都很容易。 (正确地使每个案例都很困难,但正确使用一个特定用例很容易。)

或者,如果你看一下bug #8713,我们正在做一些正常工作的工作。还有工作补丁。这些补丁是3.3,而不是2.7,所以你可能需要一些按摩,但它不应该是非常多。所以,只需cp $MY_PYTHON_LIB/multiprocessing.py $MY_PROJECT_DIR/mymultiprocessing.py,修补它,使用mymultiprocessing代替multiprocessing,并添加适当的调用以选择spawn / fork + exec /在最新补丁中调用模式之前你做了别的事。


OP说他怀疑同样的事情,所以我可能不需要向他解释这一点,但对于未来的读者:这不是Darwin与其他Unix之间的区别,而是关于Apple发布的事实许多非Unix-y中级库,如CoreFoundation.framework,Accelerate.framework等,使用不安全的分叉后功能(或者断言它们不是在fork之后使用,因为Apple不想要在他们说“从10.X开始,Foo.framework在叉子之后是安全的”之前进行严格的测试是必要的。此外,如果你比较OS X和Linux处理图形和其他硬件的方式,那么在OS X中会有更多的中级进程内用户空间。