web-dev-qa-db-ja.com

Pythonマルチプロセッシングプールマップ:AttributeError:ローカルオブジェクトをピクルできません

クラス内にループ内で多くの作業を行う必要があるメソッドがあり、すべてのコアに作業を分散させたいと考えています。

次のコードを作成しました。通常のmapを使用すると動作しますが、pool.mapはエラーを返します。

import multiprocessing
pool = multiprocessing.Pool(multiprocessing.cpu_count() - 1)

class OtherClass:
  def run(sentence, graph):
    return False

class SomeClass:
  def __init__(self):
    self.sentences = [["Some string"]]
    self.graphs = ["string"]

  def some_method(self):
      other = OtherClass()

      def single(params):
          sentences, graph = params
          return [other.run(sentence, graph) for sentence in sentences]

      return list(pool.map(single, Zip(self.sentences, self.graphs)))


SomeClass().some_method()

エラー:

AttributeError:ローカルオブジェクト 'SomeClass.some_method..single'をピクルできません

なぜsingleを漬けられないのですか? (クラス内ではなく、コンテキストに依存しないように)グローバルモジュールスコープにmovesingleしようとしました:

import multiprocessing
pool = multiprocessing.Pool(multiprocessing.cpu_count() - 1)

class OtherClass:
  def run(sentence, graph):
    return False


def single(params):
    other = OtherClass()
    sentences, graph = params
    return [other.run(sentence, graph) for sentence in sentences]

class SomeClass:
  def __init__(self):
    self.sentences = [["Some string"]]
    self.graphs = ["string"]

  def some_method(self):
      return list(pool.map(single, Zip(self.sentences, self.graphs)))


SomeClass().some_method()

そして、次のエラーが表示されます。

AttributeError: '.../test.py'からモジュール 'main'の属性 'single'を取得できません

9
Amit

関数とクラスを定義する前にプールを開始しているため、子プロセスはコードを継承できません。プールの開始位置を一番下に移動し、if __name__ == '__main__':で保護します

import multiprocessing

class OtherClass:
  def run(self, sentence, graph):
    return False


def single(params):
    other = OtherClass()
    sentences, graph = params
    return [other.run(sentence, graph) for sentence in sentences]

class SomeClass:
   def __init__(self):
       self.sentences = [["Some string"]]
       self.graphs = ["string"]

   def some_method(self):
      return list(pool.map(single, Zip(self.sentences, self.graphs)))

if __name__ == '__main__':  # <- prevent RuntimeError for 'spawn'
    # and 'forkserver' start_methods
    with multiprocessing.Pool(multiprocessing.cpu_count() - 1) as pool:
        print(SomeClass().some_method())
7
Darkonaut