2

私は、それぞれが独自の CUDA デバイスに関連付けられている複数の python プロセスに計算タスクを分散するプロジェクトに取り組んでいます。

サブプロセスを生成するときは、次のコードを使用します。

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

これは私の経験に基づいた推測にすぎませんが、OS X の CUDA (または PyCuda) の実装は、後で安全に使用できないいくつかの API に依存しているforkのに対し、Linux の実装はそうではないと思われます。子プロセスを作成せずにmultiprocessing使用するPOSIX 実装。これは、Linux ではなく OS X で失敗する理由を説明します。(また、Windows には はなく、同等のものしかないため、これは問題ではありません。)forkexecforkspawn

最も簡単な解決策は、削除することmultiprocessingです。CUDA と PyCUDA がスレッド セーフであり (そうかどうかはわかりません)、コードが CPU バウンド (GPU バウンドのみ) でない場合はthreading.Thread、代わりにドロップインして処理multiprocessing.Processを完了することができる場合があります。 . または、同様の API を提供する他の並列処理ライブラリの 1 つを検討することもできますmultiprocessingpp(いつもだからという理由だけで使う人は少ないですがexec…)

ただし、 /新しい Python インタープリターにハックしmultiprocessingて、すべてを POSIX スタイルではなく Windows スタイルで行うのは非常に簡単です。(すべてのケースを適切に処理するのは困難ですが、特定のユース ケースを適切に処理するのは簡単です。)execspawn

または、バグ #8713を見ると、この作業を一般的に正しく行うための作業が行われています。そして、作業パッチがあります。これらのパッチは 2.7 ではなく 3.3 用です。したがって、パッチを適用し、代わりにcp $MY_PYTHON_LIB/multiprocessing.py $MY_PROJECT_DIR/mymultiprocessing.py使用し、適切な呼び出しを追加して、他のことを行う前に、最新のパッチで呼び出されたモードが spawn/fork+exec/whatever であることを選択します。mymultiprocessingmultiprocessing


* OP は彼が同じことを疑ったと言っているので、おそらく彼にこれを説明する必要はありませんが、将来の読者のために: これは Darwin と他の Unix の違いに関するものではなく、Apple が多くの非- CoreFoundation.framework、Accelerate.framework などの Unix-y 中間レベルのライブラリで、分岐後の安全でない機能を使用する (または、Apple が入れたくないため、分岐後に使用されていないと主張するだけ) 「10.X の時点で、Foo.framework は fork 後も安全である」と言う前に保証される厳格なテスト)。また、OS X と Linux でグラフィックスやその他のハードウェアを処理する方法を比較すると、OS X ではプロセスごとの中間レベルのユーザー空間が多くなっています。

于 2013-02-06T00:42:14.343 に答える