2

我正在做一个项目,我将计算任务分配给多个 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

我没有在我的 Mac 上分叉新进程的情况下运行 PyCuda 脚本没有问题。我只在生成新进程时遇到这个问题。

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

4

1 回答 1

2

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

最简单的解决方案是 drop multiprocessing。如果 CUDA 和 PyCUDA 是线程安全的(我不知道它们是否是),并且您的代码不受 CPU 限制(只是受 GPU 限制),那么您也许可以直接threading.Thread代替multiprocessing.Process并完成它. 或者您可以考虑提供与multiprocessing. (有少数人使用pp只是因为它总是exec......)

但是,很容易破解multiprocessing/exec一个spawn新的 Python 解释器,然后执行 Windows 样式而不是 POSIX 样式的所有操作。(正确处理每个案例很困难,但正确处理一个特定用例却很容易。)

或者,如果您查看错误 #8713,则正在做一些工作以使这项工作正常进行。并且有工作补丁。这些补丁适用于 3.3,而不是 2.7,因此您可能需要进行一些按摩,但应该不会太多。因此,只需cp $MY_PYTHON_LIB/multiprocessing.py $MY_PROJECT_DIR/mymultiprocessing.py修补它,使用它mymultiprocessing代替multiprocessing,并添加适当的调用来选择 spawn/fork+exec/无论在你做任何其他事情之前在最新补丁中调用的模式。


* OP 说他怀疑同样的事情,所以我可能不需要向他解释这一点,但对于未来的读者:这不是关于达尔文和其他 Unix 之间的区别,而是关于苹果发布了很多非-Unix-y 中级库,如 CoreFoundation.framework、Accelerate.framework 等,它们使用 unsafe-after-fork 功能(或者只是断言它们在 fork 之后没有被使用,因为 Apple 不想放入在他们可以说“从 10.X 开始,Foo.framework 在 fork 之后是安全的”之前需要进行严格的测试)。此外,如果你比较 OS X 和 linux 处理图形和其他硬件的方式,OS X 中的每个进程用户空间中都有更多的中级。

于 2013-02-06T00:42:14.343 回答